我正在编写一个使用Threads来提高性能的简单应用程序。 问题是,这个应用程序在Windows上运行正常,使用我的CPU拥有的2个内核。但是当我在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
答案 0 :(得分:19)
clock()在windows vs 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;
}
答案 1 :(得分:8)
问题是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
答案 2 :(得分:0)
Linux“看到”线程就像进程一样,这意味着所有进程都是一个线程的线程。
在进程表(task_struct)中创建进程时创建PID,当我们创建第二个线程时,PID成为TGID(线程组ID),每个线程获得一个TID(线程ID)。 / p>
在userland中,我们只会看到第一个线程(使用ps aux)但是如果我们执行“ps -eLf”,我们将看到一个名为LWP(轻量级进程)的新列,即TID。
然后例如:
$ ps -eLf
UID PID PPID LWP C NLWP STIME TTY TIME CMD
root 1356 1 1356 0 4 2014? 00:00:00 / sbin / rsyslogd
root 1356 1 1357 0 4 2014? 00:02:01 / sbin / rsyslogd
root 1356 1 1359 0 4 2014? 00:01:55 / sbin / rsyslogd
root 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)
内核内核总是像PID一样使用TID。
之后,内核将能够使用实际并行性的每个线程使用调度。
答案 3 :(得分:-2)
这听起来像是我的OS调度程序实现。在您的代码中本身不存在问题。操作系统决定哪个线程将在哪个内核上运行,如果遵守线程/ CPU关联性规则,它每次都会将该线程粘贴在同一个CPU上。
这是一个相当复杂的主题的简单解释。