繁体   English   中英

为什么在线程中使用system()时,多线程C程序在Mac OS X上强制使用单个CPU?

[英]Why is a multithreaded C program forced to a single CPU on Mac OS X when system() is used in a thread?

我在Linux和Mac OS X之间使用pthreads的程序行为遇到了奇怪的差异。

考虑以下可以使用“gcc -pthread -o threadtest threadtest.c”编译的程序:

#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>

static
void *worker(void *t)
{
    int i = *(int *)t;

    printf("Thread %d started\n", i);
    system("sleep 1");

    printf("Thread %d ends\n", i);
    return (void *) 0;
}

int main()
{
#define N_WORKERS   4

    pthread_t       workers[N_WORKERS];
    int                 args[N_WORKERS];
    int         i;

    for (i = 0; i < N_WORKERS; ++i)
    {
        args[i] = i;
        pthread_create(&workers[i], NULL, worker, args + i);
    }

    for (i = 0; i < N_WORKERS; ++i)
    {
        pthread_join(workers[i], NULL);
    }

    return 0;
}

在4核Mac OS X计算机上运行生成的可执行文件会导致以下行为:

$ time ./threadtest
Thread 0 started
Thread 2 started
Thread 1 started
Thread 3 started
Thread 0 ends
Thread 1 ends
Thread 2 ends
Thread 3 ends

real    0m4.030s
user    0m0.006s
sys 0m0.008s

请注意,实际核心的数量可能甚至不相关,因为时间只是花在“sleep 1”shell命令中而没有任何计算。 很明显,线程是并行启动的,因为“Thread ... started”消息在程序启动后立即出现。

在Linux机器上运行相同的测试程序会得到我期望的结果:

$ time ./threadtest
Thread 0 started
Thread 3 started
Thread 1 started
Thread 2 started
Thread 1 ends
Thread 2 ends
Thread 0 ends
Thread 3 ends

real    0m1.010s
user    0m0.008s
sys 0m0.013s

并行启动四个进程,每个进程休眠一秒钟,大约需要一秒钟。

如果我将实际计算放入worker()函数并删除system()调用,我也会在Mac OS X中看到预期的加速。

所以问题是,为什么在线程中使用system()调用有效地序列化Mac OS X上的线程执行,以及如何防止这种情况?

@BasileStarynkevitch和@null指出,Mac OS X的C库中的system()实现中的全局互斥可能是观察到的行为的原因。 @null提供了对system()实现的潜在源文件的引用,其中包含以下操作:

#if __DARWIN_UNIX03
    pthread_mutex_lock(&__systemfn_mutex);
#endif /* __DARWIN_UNIX03 */

#if __DARWIN_UNIX03
    pthread_mutex_unlock(&__systemfn_mutex);
#endif /* __DARWIN_UNIX03 */

通过在lldb中反汇编system()函数,我验证了这些调用实际上存在于编译代码中。

解决方案是使用fork()/ execve()/ waitpid()系统调用的组合替换system()C库函数的使用。 在原始示例中修改worker()函数的概念的快速证明:

static
void *worker(void *t)
{
    static const char shell[] = "/bin/sh";
    static const char * const args[] = { shell, "-c", "sleep 1", NULL };
    static const char * const env[] = { NULL };

    pid_t pid;
    int i = *(int *)t;

    printf("Thread %d started\n", i);

    pid = fork();
    if (pid == 0)
    {
        execve(shell, (char **) args, (char **) env);
    }
    waitpid(pid, NULL, 0);

    printf("Thread %d ends\n", i);
    return (void *) 0;
}

通过此修改,测试程序现在可在Mac OS X上大约一秒钟执行。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM