[pthreads] Auf mehrere Threads warten



  • Hi!
    Gibt es eine Möglichkeit mit pthreads auf mehrere Threads *gleichzeitig* zu warten? Windows bietet da ja WaitForMultipleObjects.



  • threader schrieb:

    Hi!
    Gibt es eine Möglichkeit mit pthreads auf mehrere Threads *gleichzeitig* zu warten? Windows bietet da ja WaitForMultipleObjects.

    Dafür gibt es Condition Variablen. Näheres kann man sagen, wenn du es damit nicht hinbekommst.



  • Hab mit conditions mal angeschaut ... aber wie soll man damit auf mehrere Threads warten können?



  • threader schrieb:

    Hab mit conditions mal angeschaut ... aber wie soll man damit auf mehrere Threads warten können?

    Beschreib mal das konkrete Problem und worauf du genau warten möchtest.



  • Habe mich noch nie zuvor mit Thread-Programmierung beschäftigt. Hab mir deshalb mal n paar Tutorials und die manpages von pthreads angeschaut.
    Doch nirgendwo hab ich eine Funktion gefunden um auf mehrere Threads gleichzeitig zu warten.

    D.h. ich starte 20 Threads mit pthread_create(...), die irgendwelche Berechnungen machen oder in meinem Fall mit einem Socket kommunizieren.
    Diese Threads terminieren, sobald sie mit ihrer Arbeit fertig sind.

    Jetzt will ich, dass mein main-thread auf alle diese Threads *gleichzeitig* wartet und ich z.B. eine Nachricht ausgeben kann, wenn einer der anderen Threads terminiert ist.
    pthread_join(...) kann aber nur auf *einen* Thread gleichzeitig warten(bis er terminiert ist meine ich damit)

    Habe ein gegoogelt und nur eine Lösung für Win32 gefunden, und zwar in dem man mit der Funktion WaitFprMultipleObjects(http://msdn2.microsoft.com/en-us/library/ms687025.aspx) auf alle Thread-Handles wartet.

    Jetzt frag ich mich wie man soetwas mit pthreads realisiert!



  • threader schrieb:

    Jetzt frag ich mich wie man soetwas mit pthreads realisiert!

    Das ist eigentlich ganz einfach. Und es gibt wie immer mehrere Möglichkeiten.

    1. Du wartest einfach gar nicht auf die Threads. Dazu werden die einfach detached.

    2. Du verwendest eine Pipe zwischen den Threads. Ein Thread schreibt einfach seine Nummer in die Pipe und man joind dann den Richtigen.

    3. Per Condition Variable sagst du dem Master, wann ein Thread fertig ist.

    Ich mach mal gleich Beispiele.



  • So kann man es mit einer pipe machen. Beachte, dass ich nie returncodes überprüft habe.

    #include <iostream>
    
    extern "C" {
    #include <pthread.h>
    }
    
    int const THREADS = 20;
    pthread_mutex_t io_mutex = PTHREAD_MUTEX_INITIALIZER;
    int pipe_fd[2];
    
    extern "C" void * thread_run(void * arg) {
       int * id = (int *) arg;
       int wait = random() % 40 + 1;
    
       pthread_mutex_lock(&io_mutex);
       std::cout << pthread_self() << " Started thread: " << *id << std::endl;
       std::cout << pthread_self() << " Waiting: " << wait << " seconds" << std::endl;
       pthread_mutex_unlock(&io_mutex);
    
       sleep(wait);
    
       int * retval = new int(random());
    
       pthread_mutex_lock(&io_mutex);
       std::cout << pthread_self() << " Thread: " << *id << " Returning: " << *retval << std::endl;
       pthread_mutex_unlock(&io_mutex);
    
       write(pipe_fd[1], id, sizeof(int));
       delete id;
       return retval;
    }
    
    int main() {
    
       pipe(pipe_fd);
    
       pthread_t tid[THREADS];
       for (int i = 0; i < THREADS; ++i) {
          int * id = new int(i);
          pthread_create(&tid[i], NULL, thread_run, id);
       }
    
       for (int i = 0; i < THREADS; ++i) {
          int retid;
          read(pipe_fd[0], &retid, sizeof(int));
          void * retdata;
          pthread_join(tid[retid], &retdata);
          int * retval = (int *) retdata;
          pthread_mutex_lock(&io_mutex);
             std::cout << "Master: Thread: " << retid << " Joined with value: " << *retval << std::endl;
          pthread_mutex_unlock(&io_mutex);
          delete retval;
       }
    }
    


  • Und so macht man es beispielsweise mit Condition Variablen:

    #include <iostream>
    #include <vector>
    
    extern "C" {
    #include <pthread.h>
    }
    
    int const THREADS = 200;
    
    pthread_mutex_t io_mutex = PTHREAD_MUTEX_INITIALIZER;
    pthread_mutex_t join_mutex = PTHREAD_MUTEX_INITIALIZER;
    pthread_cond_t  join_cond  = PTHREAD_COND_INITIALIZER;
    
    std::vector<int> finished;
    
    extern "C" void * thread_run(void * arg) {
       int * id = (int *) arg;
       int * wait = new int(random() % 40 + 1);
    
       pthread_mutex_lock(&io_mutex);
       std::cout << pthread_self() << " Started thread: " << *id 
                 << "  Waiting: " << *wait << " seconds" << std::endl;
       pthread_mutex_unlock(&io_mutex);
    
       sleep(*wait);
    
       pthread_mutex_lock(&io_mutex);
       std::cout << pthread_self() << " Thread: " << *id << " Returning: " << *wait << std::endl;
       pthread_mutex_unlock(&io_mutex);
    
       pthread_mutex_lock(&join_mutex);
       finished.push_back(*id);
       pthread_cond_signal(&join_cond);
       pthread_mutex_unlock(&join_mutex);
       delete id;
       return wait;
    }
    
    int main() {
    
       pthread_t tid[THREADS];
       for (int i = 0; i < THREADS; ++i) {
          int * id = new int(i);
          pthread_create(&tid[i], NULL, thread_run, id);
       }
    
       for (int i = 0; i < THREADS; ++i) {
          int retid;
          pthread_mutex_lock(&join_mutex);
          while (finished.size() == 0)
             pthread_cond_wait(&join_cond, &join_mutex);
          retid = finished.back();
          finished.pop_back();
          pthread_mutex_unlock(&join_mutex);
          void * retdata;
          pthread_join(tid[retid], &retdata);
          int * retval = (int *) retdata;
          pthread_mutex_lock(&io_mutex);
             std::cout << "Master: Thread: " << retid << " Joined with value: " << *retval << std::endl;
          pthread_mutex_unlock(&io_mutex);
       }
    }
    


  • Ah, vielen Dank für dein super Beispiel, auf das mit den Pipes bin ich selber noch nicht gekommen.

    Damit wäre ja dann geklärt dass soetwas auch mit pthreads geht...

    Eine kleine Frage hab ich aber noch:
    Wie schafft es denn pthread_join auf einen Thread zu warten, ohne in einer Schleife den Thread-Status abzufragen? Diese Funktion teilt dem Aufrufer ja sozusagen "automatisch" mit, wann der Thread terminiert. Doch wie?
    Gibt es dazu vll soetwas wie atexit für Threads?



  • threader schrieb:

    Ah, vielen Dank für dein super Beispiel, auf das mit den Pipes bin ich selber noch nicht gekommen.

    Damit wäre ja dann geklärt dass soetwas auch mit pthreads geht...

    Eine kleine Frage hab ich aber noch:
    Wie schafft es denn pthread_join auf einen Thread zu warten, ohne in einer Schleife den Thread-Status abzufragen? Diese Funktion teilt dem Aufrufer ja sozusagen "automatisch" mit, wann der Thread terminiert. Doch wie?
    Gibt es dazu vll soetwas wie atexit für Threads?

    Du kannst dir pthread_cleanup_push anschauen. Aber du weisst eigentlich immer wann du einen Thread beendest und kannst so dem Master bescheid geben. Und der Master kann jederzeit, wenn es ihm passt nach beendeten Threads schauen.


Anmelden zum Antworten