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

stm:

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

考虑以下可以用“ 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;
}

在四核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命令中花费而无需任何计算。还很明显,线程是并行启动的,因为在程序启动后立即显示“线程...已启动”消息。

在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上线程的执行,如何防止这种情况发生?

stm:

@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上执行大约一秒钟。

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章

OS X中的多线程C程序比Linux慢得多

为什么notifyAll()不能在线程实例中使用?

对于任何 Win OS 上的大多数多线程应用程序,CPU 最大利用率限制为 1/N 个 CPU:为什么?

C ++ 11线程库是否调用OS API来运行多线程程序?

当在OS X上杀死Python进程时,为什么不杀死子进程呢?

当所有JAVA线程都是使用OS库创建的本机线程时,为什么要引入Fork / Join框架?

多线程中是否需要原子类型?(OS X,Clang,C ++ 11)

为什么在线程完成之前退出main()时,为什么在C中的多线程应用中出现访问冲突?

当在Linux上使用相同版本的`install`可以正常工作时,为什么在重定向输入上出现OS X`install`错误?

OS线程调度与cpu使用关系

Java线程与OS线程

为什么不能在线程宏中使用匿名函数?

为什么我们应该在线程中使用Join?

在python线程中执行os.system()会发生什么?

当使用相同的硬件时,为什么Mac OS X上的字体比Windows上的字体好看得多?

单个CPU如何处理多线程和多进程应用程序?

Go的LockOSThread为什么不锁定此OS线程?

Perl:在线程中使用eval时为空变量

为什么单个线程的Java程序有这么多线程?

在 C# 和 Mac Os X 中使用 ZMQ

为什么字体有时在Mac OS X上看起来像“胖”?

多线程(C)程序线程未终止

如何在Mac OS X 10.9上安装ZeroMQ以在C / C ++程序中使用

在Mac OS X中编译使用OpenGl的C程序

如何使用终端在Mac OS X上运行C程序?

多线程在C ++中执行单个任务

单线程CPU上的多线程应用程序?

多线程程序花费的时间比单个线程(JAVA)

为什么Mac OS X上的某些(全部?)文件更大?

TOP 榜单

热门标签

归档