我正在写一个简单的应用程序,使用线程来提高性能。 问题是,这个应用程序在Windows上运行正常,使用我的CPU有两个核心。 但是,当我在Linux上执行,似乎只使用1核心。
我不明白为什么会发生这种情况。
这些是我的代码,C ++:
#include <stdio.h> #include <stdlib.h> #include <pthread.h> #include <time.h> void* function(void*) { int i=0; for(i=0; i<1110111; i++) rand(); return 0; } void withOutThreads(void) { function(0); function(0); } void withThreads(void) { pthread_t* h1 = new pthread_t; pthread_t* h2 = new pthread_t; pthread_attr_t* atr = new pthread_attr_t; pthread_attr_init(atr); pthread_attr_setscope(atr,PTHREAD_SCOPE_SYSTEM); pthread_create(h1,atr,function,0); pthread_create(h2,atr,function,0); pthread_join(*h1,0); pthread_join(*h2,0); pthread_attr_destroy(atr); delete h1; delete h2; delete atr; } int main(void) { int ini,tim; ini = clock(); withOutThreads(); tim = (int) ( 1000*(clock()-ini)/CLOCKS_PER_SEC ); printf("Time Sequential: %d ms\n",tim); fflush(stdout); ini = clock(); withThreads(); tim = (int) ( 1000*(clock()-ini)/CLOCKS_PER_SEC ); printf("Time Concurrent: %d ms\n",tim); fflush(stdout); return 0; }
在Linux上输出:
Time Sequential: 50 ms Time Concurrent: 1610 ms
在Windows上输出:
Time Sequential: 50 ms Time Concurrent: 30 ms
clock()在windows和linux上的工作方式不同 ,所以不要用它来衡量时间。 在linux上测量CPU时间,在Windows上测量挂钟时间。 理想情况下,在这个测试案例中这些将是相同的,但是您应该使用平台之间的一些东西来衡量时间。 例如gettimeofday()
rand()在linux上序列化你的线程。 rand()拥有一个内部锁以保证线程安全。 rand()手册页状态rand()不是线程安全的,也不是可重入的,但是至少在最近的glibc中的代码获得了一个围绕该调用的锁。 我不知道Windows如何处理这个问题,要么是线程安全的,要么是使用线程局部变量。
在linux上使用rand_r,或者找一些更好的CPU使用函数来衡量。
void* function(void*) { unsigned int seed = 42; int i=0; for(i=0; i<1110111; i++) rand_r(&seed); return 0; }
问题是Linux多线程版本或rand()
锁定了互斥锁。 改变你的功能:
void* function(void*) { int i=0; unsigned rand_state = 0; for(i=0; i<1110111; i++) rand_r(&rand_state); return 0; }
输出:
Time Sequential: 10 ms Time Concurrent: 10 ms
Linux“看到”像进程这样的线程,这意味着所有进程都是一个线程的线程。
在进程表(task_struct)中,当我们创建一个进程时就会创建PID,当我们创建第二个线程时,PID变成TGID(线程组ID),每个线程获得一个TID(线程ID)。
在userland中,我们只会看到第一个线程(使用ps aux),但是如果我们执行“ps -eLf”,我们将看到一个名为LWP(轻量级进程)的新列,它是TID。
那么例如:$ ps -eLf
UID PID PPID LWP C NLWP STIME TTY TIME CMD
根1356 1 1356 0 4 2014? 00:00:00 / sbin / rsyslogd
根1356 1 1357 0 4 2014? 00:02:01 / sbin / rsyslogd
根1356 1 1359 0 4 2014? 00:01:55 / sbin / rsyslogd
根1356 1 1360 0 4 2014? 00:00:00 / sbin / rsyslogd
dbus 1377 1 1377 0 1 2014? 00:00:00 dbus-daemon
正如我们所看到的PID是一样的,但真正的PID是LWP(TID)。 当进程只有一个线程(如dbus守护进程)时,PID = LWP(TID)
内核始终使用TID,如PID。
之后,内核将能够使用真正的并行性在每个线程中使用调度。
这听起来像一个操作系统调度程序执行给我。 本身不是你的代码中的一个问题。 操作系统决定哪个线程运行在哪个内核上,如果遵循线程/ CPU关联的规则,则每次都将该线程固定在同一个CPU上。
这是一个相当复杂的主题的简单解释。