我无法将主线程同步到最近启动的子线程。
我想做的是:
我的第一次尝试是:
typedef struct threaddata_ {
int running;
} threaddata_t;
void*child_thread(void*arg) {
threaddata_t*x=(threaddata_t)arg;
/* ... INITIALIZE ... */
x->running=1; /* signal that we are running */
/* CHILD THREAD BODY */
return 0;
}
void start_thread(void) {
threaddata_t*x=(threaddata_t*)malloc(sizeof(threaddata_t));
x->running=0;
int result=pthread_create(&threadid, 0, child_thread, &running);
while(!x->running) usleep(100); /* wait till child is initialized */
/* MAIN THREAD BODY */
}
现在我根本不喜欢这样,因为它迫使主线程睡眠的时间可能比必要时间长。 所以我使用互斥和条件
进行了第二次尝试 typedef struct threaddata_ {
pthread_mutex_t x_mutex;
pthread_cond_t x_cond;
} threaddata_t;
void*child_thread(void*arg) {
threaddata_t*x=(threaddata_t)arg;
/* ... INITIALIZE ... */
pthread_cond_signal(&x->x_cond); /* signal that we are running */
/* CHILD THREAD BODY */
return 0;
}
void start_thread(void) {
threaddata_t*x=(threaddata_t*)malloc(sizeof(threaddata_t));
pthread_mutex_init(&x->x_mutex, 0);
pthread_cond_init (&x->x_cond , 0);
pthread_mutex_lock(&x->x_mutex);
int result=pthread_create(&threadid, 0, child_thread, &running);
if(!result)pthread_cond_wait(&x->x_cond, &x->x_mutex);
pthread_mutex_unlock(&x->x_mutex);
/* MAIN THREAD BODY */
}
这似乎比第一次尝试(使用适当的信号而不是滚动自己的等待循环)更加理智,直到我发现,这包括竞争条件: 如果子线程已经足够快地完成初始化(在主线程等待条件之前),它将使主线程死锁。
我想我的情况并非如此罕见,所以必须有一个非常简单的解决方案,但我现在看不到它。
答案 0 :(得分:7)
condvar /互斥对使用的正确方法:
bool initialised = false;
mutex mt;
convar cv;
void *thread_proc(void *)
{
...
mt.lock();
initialised = true;
cv.signal();
mt.unlock();
}
int main()
{
...
mt.lock();
while(!initialised) cv.wait(mt);
mt.unlock();
}
此算法可避免任何可能的比赛。您可以使用在锁定互斥锁时修改的任何复杂条件(而不是简单的!初始化)。
答案 1 :(得分:2)
正确的工具是sem_t
。 main
线程将使用0
初始化它们,并等待它从新启动的线程接收到令牌。
BTW你的互斥锁/ cond解决方案有竞争条件,因为子线程没有锁定互斥锁。
答案 2 :(得分:2)
障碍应该很好地完成这个伎俩。由于您在评论中提到了对Win32的支持需求,因此最新的Win32 pthreads支持障碍,因此您不必编写自己的包装器以在Win32和* nix之间获得一些可移植性。
类似的东西:
typedef struct threaddata_ {
pthread_barrier_t* pbarrier;
} threaddata_t;
void* child_thread(void*arg) {
threaddata_t*x=(threaddata_t*)arg;
/* ... INITIALIZE ... */
int result = pthread_barrier_wait(x->pbarrier);
/* CHILD THREAD BODY */
return 0;
}
void start_thread(void) {
pthread_barrier_t barrier;
int result = pthread_barrier_init(&barrier, NULL, 2);
threaddata_t*x=(threaddata_t*)malloc(sizeof(threaddata_t));
x->pbarrier = &barrier;
int result=pthread_create(&threadid, 0, child_thread, &x);
result = pthread_barrier_wait(&barrier);
/* child has reached the barrier */
pthread_barrier_destroy(&barrier); /* note: the child thread should not use */
/* the barrier pointer after it returns from*/
/* pthread_barrier_wait() */
/* MAIN THREAD BODY */
}
这种解决方案的缺点是它可能会不必要地暂时阻塞子线程。如果这是一个问题,那么condition variable solution mentioned by Dmitry Poroh就可以了。