【发布时间】:2015-07-01 10:36:53
【问题描述】:
我发现在 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;
}
在 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 上的线程执行,以及如何防止这种情况发生?
【问题讨论】:
-
也许 MacOSX 上的标准 C 库可能是免费软件,所以你可以瞥见他们对
system的实现(我可能猜他们正在使用一些全局互斥锁,但我不明白为什么) .否则,选择system的一些免费软件实现 -
@BasileStarynkevitch Not sure if this is the right source file 但里面有一个互斥锁。
-
一般来说,从线程内部调用 C 库函数是一个非常糟糕的主意。来自 C11 标准(支持线程):
The functions in the standard library are not guaranteed to be reentrant and may modify objects with static or thread storage duration. -
@null 好的,我在 system.c 的实现中看到了互斥锁。当我在 dtruss 下运行程序时,我也可以看到互斥体的参与。
-
@BasileStarynkevitch 我将寻找 system() 内部发生的事情的重新实现。看来有必要直接使用 fork()/exec()/wait() 系统调用。
标签: c++ c linux multithreading macos