我的问题类似于How do I check if a thread is terminated when using pthread?。但我没有得到答案。
我的问题是......我创建了一定数量的线程说n。一旦main检测到任何一个线程的退出,它就会创建另一个线程,从而将并发度保持为n,依此类推。
主线程如何检测线程的退出。 pthread_join等待一个特定的线程退出但在我的情况下它可以是n个线程中的任何一个。
谢谢
答案 0 :(得分:3)
最明显的是,如果没有按照aix的建议重构你的代码,就是让每个线程设置一些东西来表示它已经完成(可能是所有线程之间共享的数组中的值,每个工作线程一个槽),然后发出信号a条件变量。主线程等待条件变量,每次唤醒时,处理所有表明自己完成的线程:可能有多个。
当然这意味着如果线程被取消,你永远不会收到信号,所以使用取消处理程序或不取消线程。
答案 1 :(得分:2)
有几种方法可以解决这个问题。
一种自然的方法是拥有一个固定大小n
的线程池,并且有一个队列,主线程将在其中放置任务,工作人员将从中获取任务并处理它们。这将保持恒定的并发度。
另一种方法是使用一个初始值设置为n
的信号量。每次创建工作线程时,都需要递减信号量的值。每当工人即将终止时,都需要增加(“发布”)信号量。现在,等待主线程中的信号量将被阻塞,直到剩下少于n
个工作人员;然后生成一个新的工作线程并等待恢复。由于您不会对工作人员使用pthread_join
,因此应将其分离(pthread_detach
)。
答案 2 :(得分:0)
如果您希望被告知退出的线程(通过pthread_exit
或取消),您可以使用pthread_cleanup_push
处理程序通知子进程的主线程(通过条件变量,信号量或类似的)所以它可以等待它,或者只是开始一个新的(假设孩子先分离)。
或者,我建议让线程等待更多的工作(如@aix所建议的那样),而不是结束。
答案 3 :(得分:0)
如果你的父线程需要做其他事情,那么它不能只是在pthread_join
上不断阻塞,你需要一种方法从子线程向主线程发送消息来告诉它致电pthread_join
。您可以使用许多IPC机制。
当子线程完成它的工作时,它会通过IPC向主线程发送某种消息,说“我完成了我的工作”并传递了自己的线程ID,然后主线程知道调用{{ 1}}在那个线程id。
答案 4 :(得分:0)
一种简单的方法是使用管道作为(工作者)线程与主线程之间的通信通道。当一个线程终止时,它会将其结果(以下示例中的线程ID)写入管道。主线程在管道上等待,并在它可用时立即从中读取线程结果。
与互斥锁或信号量不同,应用程序主事件循环(例如libevent)可以轻松处理管道文件描述符。只要写入PIPE_BUF
或更少的字节(在我的Linux上为4096),从不同线程到同一管道的写入都是原子的。
下面是一个演示,它创建了十个线程,每个线程具有不同的生命周期。然后主线程等待任何线程终止并打印其线程ID。当所有十个线程都完成时它终止。
$ cat test.cc
#include <iostream>
#include <pthread.h>
#include <unistd.h>
#include <stdlib.h>
#include <time.h>
void* thread_fun(void* arg) {
// do something
unsigned delay = rand() % 10;
usleep(delay * 1000000);
// notify termination
int* thread_completed_fd = static_cast<int*>(arg);
pthread_t thread_id = pthread_self();
if(sizeof thread_id != write(*thread_completed_fd, &thread_id, sizeof thread_id))
abort();
return 0;
}
int main() {
int fd[2];
if(pipe(fd))
abort();
enum { THREADS = 10 };
time_t start = time(NULL);
// start threads
for(int n = THREADS; n--;) {
pthread_t thread_id;
if(pthread_create(&thread_id, NULL, thread_fun, fd + 1))
abort();
std::cout << time(NULL) - start << " sec: started thread " << thread_id << '\n';
}
// wait for the threads to finish
for(int n = THREADS; n--;) {
pthread_t thread_id;
if(sizeof thread_id != read(fd[0], &thread_id, sizeof thread_id))
abort();
if(pthread_join(thread_id, NULL)) // detached threads don't need this call
abort();
std::cout << time(NULL) - start << " sec: thread " << thread_id << " has completed\n";
}
close(fd[0]);
close(fd[1]);
}
$ g++ -o test -pthread -Wall -Wextra -march=native test.cc
$ ./test
0 sec: started thread 140672287479552
0 sec: started thread 140672278759168
0 sec: started thread 140672270038784
0 sec: started thread 140672261318400
0 sec: started thread 140672252598016
0 sec: started thread 140672243877632
0 sec: started thread 140672235157248
0 sec: started thread 140672226436864
0 sec: started thread 140672217716480
0 sec: started thread 140672208996096
1 sec: thread 140672208996096 has completed
2 sec: thread 140672226436864 has completed
3 sec: thread 140672287479552 has completed
3 sec: thread 140672243877632 has completed
5 sec: thread 140672252598016 has completed
5 sec: thread 140672261318400 has completed
6 sec: thread 140672278759168 has completed
6 sec: thread 140672235157248 has completed
7 sec: thread 140672270038784 has completed
9 sec: thread 140672217716480 has completed