Pthread_join中的一个线程之一

时间:2011-09-05 16:45:20

标签: c linux pthreads

我的问题类似于How do I check if a thread is terminated when using pthread?。但我没有得到答案。

我的问题是......我创建了一定数量的线程说n。一旦main检测到任何一个线程的退出,它就会创建另一个线程,从而将并发度保持为​​n,依此类推。

主线程如何检测线程的退出。 pthread_join等待一个特定的线程退出但在我的情况下它可以是n个线程中的任何一个。

谢谢

5 个答案:

答案 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