如何检测提前退出pthread_create没有阻塞太久?

我有一个叫做mainloop的线程

 int run_mainloop; void* mainloop(void* param) { // local vars // initialize local vars while(run_mainloop) { // run mainloop } return 0; } 

线程从一个名为client_open的函数中被client_open ,即

 int client_open() { run_mainloop = 1; return pthread_create(&thread, NULL, mainloop, NULL); } 

但是,在mainloop如果初始化局部variables失败,我需要立即通知client_open提前退出。

pthread_join是不合适的,因为它会阻塞,我不能有client_open块。 如果是在等待很短的时间才能回来,那就OK了。

我怎么能这样做,而不使用pthread_join将阻止。 我希望能够得到返回码。

使用pthread_tryjoin_np将是不正确的:新线程可以任意延迟pthread_create返回,和新线程实际执行初始化代码。

如果你在这个延迟期间执行了pthread_tryjoin_np ,那么连接将会失败,并且你会决定一切都是“确定的”,而事实上并非如此。

你想要的是一个条件: client_open将等待它,主mainloop会发信号(完成初始化)。

你可以使用一些已知的完成变量

一个线程可以等待一个新创建的线程完成初始化。 唯一的问题是,即使初始化失败,新线程也必须始终表示初始化完成。

一些事情沿着下面的行(错误处理被省略为了清楚):

 #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); } 

好的,我发现了三种方法来做到这一点。

1)在启动之前初始化并传递变量到主循环。

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; }