C pthread_创建写回计时

C pthread_创建写回计时,c,pthreads,race-condition,C,Pthreads,Race Condition,在调用pthread_create(&id,NULL,&start_例程,arg)中,是否保证在start_例程开始运行之前将线程id写入id?手册页很清楚,在pthread_create调用返回之前,start_例程可能会但不一定会开始执行,但是当线程id被写回传递的线程参数时,这些手册页是静默的 我的具体情况是,我在pthread_create周围有一个包装器: int mk_thread(pthread_t *id) { pthread_t tid; pthread_create(

在调用pthread_create(&id,NULL,&start_例程,arg)中,是否保证在start_例程开始运行之前将线程id写入id?手册页很清楚,在pthread_create调用返回之前,start_例程可能会但不一定会开始执行,但是当线程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);
  }
}

这种重写在实践中要稳定得多,但它实际上是一种修复,还是只是一个较小的争用条件窗口?

线程id肯定是在
pthread\u create
返回之前写入的。如果您仔细想想,那么
pthread\u create
不可能以任何其他方式工作。它无法将线程id的写入委托给新线程,因为新线程运行时,
pthread\u t
变量可能超出范围

有关案文如下:

成功完成后,pthread_create()应将创建线程的ID存储在线程引用的位置

(From)注意,它表示功能“成功完成”,而不是“成功完成后的不确定时间”

更有趣的问题是,
pthread_create
是否必须在新线程启动函数开始之前将线程id写入其目标,也就是说,新线程是否可以立即看到自己的线程id,例如,它是否要存储在全局变量中。我怀疑答案是否定的


编辑:重读您的问题时,您似乎真的在问后一个更有趣的问题。在任何情况下,新线程的start函数都没有理由使用
pthread\u create
写出的线程id。您的新线程可以(也应该)只使用
pthread\u self
来获取自己的线程id。

我相信规范中没有任何内容要求pthread\u create在
开始执行例程
中的代码之前分配其输出参数
pthread\u t*thread

实际上,以下程序在许多pthreads实现(freebsd8 i386和debian gnu/linux amd64)上成功,但在我感兴趣的一个实现(debian/kfreebsd9 amd64)上失败:

#包括
#包括
#包括
#包括
pthread_t th;
作废*资产(作废*未使用){
pthread_t self=pthread_self(),th_uu=th;
printf(“th=%jd self=%jd\n”,(intmax_t)th_(intmax_t)self);
断言(pthread_equal(th_,self));
}
int main(){
int i;

对于(i=0;i不存在pthread_self()要查看线程自己的ID?我认为问题出在其他地方。竞态条件只能在不同线程之间出现,而不是在单个线程内。因此,我相信,如果OP询问线程ID是否已被及时写入以供新线程查看,那么这个问题才有意义。通过新线程只需使用
pthread\u self
来获取自己的线程id。是的,竞态条件只能在不同的线程或进程上实现。但是,通常通过锁定互斥体而不是跟踪线程id来解决。但是,嘿,我们没有看到竞态条件出现的代码,我想我最好暂时不使用它。pthread_self()在这里没有帮助,因为它不是需要知道自己id的新线程,而是任何正在运行的线程可能会检查运行线程的全局(是的,受互斥保护)列表,以了解可以加入哪些线程。啊,我终于找到了一个版本的引用,其中包含来自“在新创建的线程开始执行之前,不需要在实现中提供已创建线程的ID。”这用一个明确的编号回答了我的“是否安全”问题。因此,为了正确起见,我的应用程序需要以不同的方式获取ID(例如让启动例程立即休眠,并在复制回id后收到信号)您确定第二个例程更稳定吗?我注意到第2行有一个拼写错误,其中tidPtr应该是一个指针,而它缺少一个星号。另外,变量“lid”中有什么“?我很懒,是手工输入的。真正的代码没有这些输入错误。第一个代码中的“lid”应该是“tid”,第二个代码中缺少*是的。别忘了检查
pthread\u create
的返回值,看它是否成功。
#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;
}