我如何等待任何/所有的pthreads完成?

我只想让我的主线程在退出之前等待任何和所有的(p)线程完成。

线程出入有很多原因不同,我真的不想跟踪所有这些 – 我只是想知道他们什么时候都走了。

wait()为subprocess执行此操作,在没有subprocess的情况下返回ECHILD,但wait并不(看起来像)(p)线程。

我真的不想经历保持每一个未完成的线程列表的麻烦(因为他们来来去去),然后不得不每个调用pthread_join。

有没有一个快速和肮脏的方法来做到这一点?

Solutions Collecting From Web of "我如何等待任何/所有的pthreads完成?"

正确的方法是跟踪你所有的pthread_id,但是你要求一个快速和肮脏的方式,所以这里。 基本上:

  • 只是保持运行线程的总数,
  • 在调用pthread_create之前,在主循环中增加它,
  • 在每个线程完成时递减线程计数。
  • 然后在主进程结束之前休眠,直到计数返回到0。

volatile int running_threads = 0; pthread_mutex_t running_mutex = PTHREAD_MUTEX_INITIALIZER; void * threadStart() { // do the thread work pthread_mutex_lock(&running_mutex); running_threads--; pthread_mutex_unlock(&running_mutex); } int main() { for (i = 0; i < num_threads;i++) { pthread_mutex_lock(&running_mutex); running_threads++; pthread_mutex_unlock(&running_mutex); // launch thread } while (running_threads > 0) { sleep(1); } } 

在所有的线程完成之后,你是否希望你的主线程特别做任何事情?

如果没有,你可以让主线程调用pthread_exit()而不是返回(或调用exit() )。

如果main()隐式方式返回,则调用(或者像调用它的行为) exit() ,这将终止进程。 但是,如果main()调用pthread_exit()而不是返回,那么对exit()隐式调用不会发生,并且进程不会立即结束 – 当所有线程都终止时,它将结束。

不能得到太多的肮脏。

这里有一个小例子程序,可以让你看到不同之处。 将-DUSE_PTHREAD_EXIT传递给编译器以查看进程等待所有线程完成。 编译没有定义宏来查看进程停止线程在他们的轨道。

 #include <stdio.h> #include <stdlib.h> #include <pthread.h> #include <time.h> static void sleep(int ms) { struct timespec waittime; waittime.tv_sec = (ms / 1000); ms = ms % 1000; waittime.tv_nsec = ms * 1000 * 1000; nanosleep( &waittime, NULL); } void* threadfunc( void* c) { int id = (int) c; int i = 0; for (i = 0 ; i < 12; ++i) { printf( "thread %d, iteration %d\n", id, i); sleep(10); } return 0; } int main() { int i = 4; for (; i; --i) { pthread_t* tcb = malloc( sizeof(*tcb)); pthread_create( tcb, NULL, threadfunc, (void*) i); } sleep(40); #ifdef USE_PTHREAD_EXIT pthread_exit(0); #endif return 0; } 

如果你不想跟踪你的线程,那么你可以分离线程,所以你不必关心它们,但为了告诉它们什么时候完成,你将不得不进一步。

一个技巧是保持线程状态的列表(链表,数组,任何)。 当线程启动时,它将数组中的状态设置为类似于THREAD_STATUS_RUNNING的状态,并在结束之前将其状态更新为THREAD_STATUS_STOPPED之类的状态。 然后当你想检查是否所有的线程都停止了,你可以迭代这个数组并检查所有的状态。

不要忘记,如果你这样做,你将需要控制对数组的访问,以便一次只有一个线程可以访问(读写),所以你需要使用一个互斥体。

你可以保留一个列表所有的线程标识符,然后在每个线程标识符上执行pthread_join,当然你需要一个互斥体来控制对线程标识符列表的访问。 你还需要一些可以在迭代时修改的列表,也许是一个std :: set <pthread_t>?

 int main() { pthread_mutex_lock(&mutex); void *data; for(threadId in threadIdList) { pthread_mutex_unlock(&mutex); pthread_join(threadId, &data); pthread_mutex_lock(&mutex); } printf("All threads completed.\n"); } // called by any thread to create another void CreateThread() { pthread_t id; pthread_mutex_lock(&mutex); pthread_create(&id, NULL, ThreadInit, &id); // pass the id so the thread can use it with to remove itself threadIdList.add(id); pthread_mutex_unlock(&mutex); } // called by each thread before it dies void RemoveThread(pthread_t& id) { pthread_mutex_lock(&mutex); threadIdList.remove(id); pthread_mutex_unlock(&mutex); } 

感谢所有伟大的答案! 有很多关于使用内存障碍的讨论 – 所以我想我会张贴一个答案,正确地显示他们用于此。

 #define NUM_THREADS 5 unsigned int thread_count; void *threadfunc(void *arg) { printf("Thread %p running\n",arg); sleep(3); printf("Thread %p exiting\n",arg); __sync_fetch_and_sub(&thread_count,1); return 0L; } int main() { int i; pthread_t thread[NUM_THREADS]; thread_count=NUM_THREADS; for (i=0;i<NUM_THREADS;i++) { pthread_create(&thread[i],0L,threadfunc,&thread[i]); } do { __sync_synchronize(); } while (thread_count); printf("All threads done\n"); } 

请注意,__sync宏是“非标准”GCC内部宏。 LLVM也支持这些 – 但是如果你使用另一个编译器,你可能不得不做一些不同的事情。

另一件值得注意的事情是:为什么要烧掉整个核心,或者浪费一半的CPU在紧密的轮询循环中等待其他人完成 – 当你可以轻松地将其工作? 下面的mod使用初始线程来运行其中一个worker,然后等待其他人完成:

  thread_count=NUM_THREADS; for (i=1;i<NUM_THREADS;i++) { pthread_create(&thread[i],0L,threadfunc,&thread[i]); } threadfunc(&thread[0]); do { __sync_synchronize(); } while (thread_count); printf("All threads done\n"); } 

请注意,我们开始创建从“1”而不是“0”开始的线程,然后直接运行“线程0”内联,等待所有线程完成后。 我们将线程[0]传递给它以保持一致性(即使这里没有意义),尽管实际上你可能会传递你自己的变量/上下文。