我只希望我的主线程在退出之前等待任何和所有我的(p)线程完成。
由于不同的原因,线程出现了很多,我真的不想跟踪所有这些 - 我只是想知道它们什么时候都消失了。
wait()为子进程执行此操作,在没有子进程时返回ECHILD,但是等待没有(似乎可以使用)(p)线程。
我真的不想麻烦地保留每个未完成线程的列表(因为它们来来去去),然后不得不在每个线程上调用pthread_join。
有一种快速而肮脏的方法吗?
答案 0 :(得分:26)
您是否希望主线程在所有线程完成后特别做任何事情?
如果没有,您可以让主线程只需拨打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;
}
答案 1 :(得分:23)
正确的方法是跟踪你所有的pthread_id,但是你要求快速而肮脏的方式,所以这里是。基本上是:
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);
}
}
答案 2 :(得分:2)
如果您不想跟踪线程,那么您可以分离线程,这样您就不必关心它们了,但是为了告诉它们什么时候完成,您将需要更进一步。
一个技巧是保留线程状态的列表(链表,数组等等)。当线程启动时,它将其在数组中的状态设置为THREAD_STATUS_RUNNING,并在它结束之前将其状态更新为THREAD_STATUS_STOPPED。然后,当你想检查所有线程是否已经停止时,你可以迭代这个数组并检查所有状态。
不要忘记,如果你做这样的事情,你需要控制对数组的访问,这样一次只有一个线程可以访问它(读和写),所以你需要在它上面使用互斥锁。
答案 3 :(得分:1)
你可以保存所有线程ID的列表,然后在每个线程ID上执行pthread_join, 当然,您需要一个互斥锁来控制对线程ID列表的访问。你会 还需要某种可以在迭代时修改的列表,也许是std :: set&lt; pthread_t&gt;?
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);
}
答案 4 :(得分:0)
感谢所有人的好消息!有很多关于使用内存障碍等的讨论 - 所以我想我会发布一个正确显示它们用于此的答案。
#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宏是&#34;非标准&#34; GCC内部宏。 LLVM也支持这些 - 但如果你使用其他编译器,你可能需要做一些不同的事情。
另一个需要注意的重要事项是:为什么要烧掉整个核心,或者浪费掉一半&#34;一个CPU在一个紧密的轮询循环中旋转,等待其他人完成 - 当你可以轻松地将其投入使用?以下mod使用初始线程来运行其中一个worker,然后等待其他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");
}
请注意,我们从&#34; 1&#34;开始创建线程。而不是&#34; 0&#34;,然后直接运行&#34;线程0&#34;内联,等待所有线程完成后完成。我们将&amp; thread [0]传递给它以保持一致性(即使它在这里毫无意义),但实际上你可能会传递自己的变量/上下文。