在调用pthread_create(& id,NULL,& start_routine,arg)中,是否保证在start_routine开始运行之前将线程ID写入id?联机帮助页很清楚start_routine可能但不一定会在调用pthread_create之前开始执行,但是当线程id被写回到传递的线程参数时,它们是静默的。
我的具体情况是我有一个pthread_create包装器:
int mk_thread(pthread_t *id) {
pthread_t tid;
pthread_create(&tid,NULL,ThreadStart,NULL);
if (id == NULL) {
pthread_detach(tid);
} else {
*id=lid;
}
}
显然可以在写回之前运行启动例程。我把它改成了
int mk_thread(pthread_t *id) {
pthread_t tid,tidPtr=id?id:&tid;
pthread_create(tidPtr,NULL,ThreadStart,NULL);
if (id == NULL) {
pthread_detach(tid);
}
}
这种重写在实践中要稳定得多,但它实际上是一个修复还是只是一个较小的竞争条件窗口?
答案 0 :(得分:2)
线程ID肯定是在pthread_create
返回之前写的。如果你考虑一下,pthread_create
就不可能以任何其他方式工作。它无法委托将线程id写入新线程,因为pthread_t
变量可能在新线程运行时超出范围。
相关文字是:
成功完成后,pthread_create()会将创建的线程的ID存储在线程引用的位置。
(来自http://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_create.html)请注意,它表示“成功完成”该功能,而不是“成功完成后的不确定时间”。
更有趣的问题,我不清楚这个问题,是pthread_create
是否必须在新线程启动函数开始之前将线程id写入其目标,即新线程是否可以立即看到它自己的线程ID,例如如果它要存储在全局变量中。我怀疑答案是肯定的。
编辑:在重新阅读您的问题时,您可能真的一直在询问后一个更有趣的问题。在任何情况下,新线程的启动函数都没有理由使用pthread_create
写出的线程标识。您的新线程可以(而且应该)使用pthread_self
来获取自己的线程ID。
答案 1 :(得分:0)
我相信规范中没有任何内容要求pthread_create在pthread_t *thread
中的代码开始执行之前分配其输出参数start_routine
。
作为一个实际问题,下面的程序在许多pthreads实现上成功(freebsd8 i386和debian gnu / linux amd64),但对我感兴趣的是失败(debian / kfreebsd9 amd64):
#include <pthread.h>
#include <assert.h>
#include <stdint.h>
#include <stdio.h>
pthread_t th;
void *asserter(void* unused) {
pthread_t self = pthread_self(), th_=th;
printf("th=%jd self=%jd\n", (intmax_t)th_, (intmax_t)self);
assert(pthread_equal(th_, self));
}
int main() {
int i;
for(i=0; i<1000; i++) {
pthread_create(&th, NULL, asserter, NULL);
pthread_join(th, NULL);
}
return 0;
}
说,我不确定我是否理解这个行为细节如何与您在原始问题中提供的两种代码替代相关。虽然我发现如果pthread_create在执行期间将其他值写入*thread
,并且您在另一个线程中使用*id
的值,则可能是相关的。该标准未指定在成功执行pthread_create期间没有其他“中间”值写入*thread
。