我有一个名为mainloop
即
int run_mainloop;
void* mainloop(void* param)
{
// local vars
// initialize local vars
while(run_mainloop)
{
// run mainloop
}
return 0;
}
线程从名为client_open
的函数开始,即
int client_open()
{
run_mainloop = 1;
return pthread_create(&thread, NULL, mainloop, NULL);
}
但是,在mainloop
中,如果初始化局部变量失败,我需要立即通知client_open
提前退出。
pthread_join
不合适,因为它会阻止,我无法client_open
阻止。
如果要在返回之前等待一小段时间就可以了。
如果不使用会阻塞的pthread_join,我怎么能以一种很好的方式做到这一点。 我希望能够获得返回码。
答案 0 :(得分:4)
使用pthread_tryjoin_np
是不正确的:新线程可以在pthread_create
返回和新线程实际执行初始化代码之间任意延迟。
如果您在此延迟期间pthread_tryjoin_np
,则加入将失败,您将确定所有内容都是“正常”,而实际上并非如此。
你想要的是一个条件:client_open
将等待它,mainloop
将发出信号(完成初始化后)。
答案 1 :(得分:4)
您可以使用称为completion variables的内容。
使用哪个线程可以等到新创建的线程完成初始化。唯一的问题是,即使初始化失败,新线程也必须始终发出初始化完成信号。
以下几行(为清晰起见,省略了错误处理):
#include <pthread.h>
// Completion variable definition:
typedef struct {
pthread_mutex_t mtx;
pthread_cond_t cnd;
int completed;
int return_code;
} Completion;
#define COMPLETION_INIT { PTHREAD_MUTEX_INITIALIZER, PTHREAD_COND_INITIALIZER, 0, 0 }
int completion_wait(Completion* c) { // add timeout if necessary
pthread_mutex_lock(&c->mtx);
while(!c->completed)
pthread_cond_wait(&c->cnd, &c->mtx);
int return_code = c->return_code;
pthread_mutex_unlock(&c->mtx);
return return_code;
}
void completion_signal(Completion* c, int return_code) {
pthread_mutex_lock(&c->mtx);
c->completed = 1;
c->return_code = return_code;
pthread_cond_signal(&c->cnd);
pthread_mutex_unlock(&c->mtx);
}
// Usage:
void* mainloop(void* vc) {
int init_success = 0;
// initialization
// ...
init_success = 1;
init_end:
Completion* c = (Completion*)vc;
completion_signal(c, init_success); // always signal
if(!init_success)
return NULL;
// start the main loop
return NULL;
}
int client_open()
{
int run_mainloop = 1;
pthread_t thread;
Completion c = COMPLETION_INIT;
pthread_create(&thread, NULL, mainloop, &c);
pthread_detach(thread);
return completion_wait(&c);
}
答案 2 :(得分:-1)
好的,我发现了三种方法。
1)在启动之前初始化并将变量传递给mainloop。
2)使用Linux特定的pthread_tryjoin_np()或pthread_timedjoin_np() 我认为定时连接版本在这种情况下更合适,因为它允许创建线程的时间和完成初始化。超时不需要很长,因此它不会将调用者阻塞到client_open()很长时间。
然而,正如@fge指出的那样,它们是不可移植的。虽然这不是一个太大的问题,但我想到了另一种方法。
编辑:不是一个很好的解决方案,但留在这里供参考。 最好使用初始化正常的条件变量来打开信号。
3)检查run_mainloop是否为非零,如果是,并且pthread_create没有失败且线程正在运行。如果它在一段时间后仍然为零,那么它没有启动,所以我们调用pthread_join来获取退出代码。
int run_mainloop = 0;
void* mainloop(void* param)
{
// init vars
// if failure, exit early.
// everything from this point on is good.
run_mainloop = 1;
while (run_mainloop))
{
// do styff
}
return 0;
}
int client_open()
{
void* res;
int rc = pthread_create(&g_thread_id, NULL, mainloop, NULL);
if (rc != 0)
return -1;
usleep(100); // wait a little while, kinda dumb but allows time for init
if (run_mainloop))
return 0;
pthread_join(g_thread_id, &res);
return -1;
}