PThreads& Linux上的MultiCore CPU

时间:2011-02-21 16:47:17

标签: c++ c linux pthreads

我正在编写一个使用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

4 个答案:

答案 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上。

这是一个相当复杂的主题的简单解释。