簡體   English   中英

Pthread_join中的一個線程之一

[英]Pthread_join of one of a number of threads

我的問題類似於如何在使用pthread時檢查線程是否被終止? 但我沒有得到答案。

我的問題是......我創建了一定數量的線程說n。 一旦main檢測到任何一個線程的退出,它就會創建另一個線程,從而將並發度保持為​​n,依此類推。

主線程如何檢測線程的退出。 pthread_join等待特定線程退出但在我的情況下它可以是n個線程中的任何一個。

謝謝

最明顯的是,如果沒有按照aix的建議重構你的代碼,就是讓每個線程設置一些東西來表明它已經完成(可能是所有線程之間共享的數組中的值,每個工作線程一個槽),然后發出一個條件變量信號。 主線程等待條件變量,每次喚醒時,處理所有表明自己完成的線程:可能有多個。

當然這意味着如果線程被取消,你永遠不會發出信號,所以使用取消處理程序或不取消線程。

有幾種方法可以解決這個問題。

一種自然的方法是擁有一個固定大小為n的線程池,並有一個隊列,主線程將放置任務,工作人員將從中挑選任務並處理它們。 這將保持恆定的並發度。

另一種方法是使用一個初始值設置為n的信號量。 每次創建工作線程時,都需要遞減信號量的值。 每當工人即將終止時,都需要增加(“發布”)信號量。 現在,等待主線程中的信號量將被阻塞,直到剩下的工人少於n ; 然后生成一個新的工作線程並等待恢復。 由於您不會在worker上使用pthread_join ,因此應將它們分離( pthread_detach )。

如果你想通知一個線程退出(通過pthread_exit或者取消),你可以使用一個帶有pthread_cleanup_push的處理程序來通知子線程的主線程(通過條件變量,信號量或類似物),這樣它就可以等待它,或只是開始一個新的(假設孩子先分離)。

或者,我建議讓線程等待更多工作(如@aix所示),而不是結束。

如果你的父線程需要做其他事情,那么它不能只是在pthread_join上不斷阻塞,你需要一種方法從子線程向主線程發送一條消息,告訴它調用pthread_join 您可以使用許多IPC機制。

當一個子線程完成它的工作時,它會通過IPC發送某種消息到主線程說“我完成了我的工作”並傳遞了自己的線程id,然后主線程知道在該線程id上調用pthread_join

一種簡單的方法是使用管道作為(工作者)線程和主線程之間的通信通道。 當一個線程終止時,它會將其結果(以下示例中的線程ID)寫入管道。 主線程在管道上等待,並在它可用時立即從中讀取線程結果。

與互斥鎖或信號量不同,應用程序主事件循環(例如libevent)可以輕松處理管道文件描述符。 只要寫入PIPE_BUF或更少的字節(我的Linux上為4096),從不同線程到同一管道的寫入都是原子的。

下面是一個演示,它創建了10個線程,每個線程具有不同的生命周期。 然后主線程等待任何線程終止並打印其線程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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM