A commonly used
  parallel programming pattern
  
  
  
  
  
  
  
  
  
  
  
  
  
   | 
   A commonly used
       parallel programming
       pattern:
 
 | 
   main( )
   {
       Prepare data1;
       Spawn N "worker" threads to process data1;
       Wait for all threads to complete processing
       Prepare data2;
       Spawn N "worker" threads to process data2;
       Wait for all threads to complete processing
       ....
   }
 |  
 Graphical
     depiction of
    each step:
   
   | 
  
  
  
  
  
  
  
  
  
  
 
  
  
  
  
  
  
  Detached and
   Joinable
   threads
  
  
  
  
  
  
  
  
  
  
  
  
  
   | 
   There are 
   
   2 kinds of
    
    threads in
    the PThread API:
 
 | 
  Detached 
     threads
  Joinable
     threads
  |  
 
 
   
   Detached
   threads:
 
 | 
  A detached
   thread is an
     "independent" 
     thread
 
  When a 
      detached 
   thread 
  
    terminates, its
       resources
   are  
  
    released back
    to the system
   
    immediately
  |  
   
   Joinable
   threads:
 
 | 
  A joinable
   thread is a
     "dependent" 
     thread
 
  When a 
      joinable 
   thread 
  
    terminates, its
       resources
   are  
  
    retained until
    
    the thread
    
    joins
    with its
    creator thread
  |  
 
 
 The 
   
    default
   setting of
  
   pthread_create( ) will
   create a
  
   joinable
   thread
   | 
  
  
  
  
  
  
  
  
  
  
 
  
  
  
  
  
  
  How to
  "join" (= wait for) a
  joinable thread
  to finish
  
  
  
  
  
  
  
  
  
  
  
  
  
   | 
   When the main thread
       
     creates a
       "worker" thread, it must
       
    record its
       thread ID:
 
 | 
    pthread_t tid;
    if ( pthread_create(&tid, NULL, worker, &n) != 0 )  // Create thread
    {
        perror("pthread_create");  // Print error message
        exit(1);
    }
 |  
 The main thread can
     "join" (= wait for)
     a joinable thread with the
     
     pthread_join( )
     call:
 
 | 
  pthread_join(pthread_t threadID, void **retval);
 
     threadID = the thread ID returned by pthread_create( )
     retval   = return value returned by the exiting thread
  Example:
       pthread_join( tid, NULL );   // NULL = ignore the return value
 |  
   | 
  
  
  
  
  
  
  
  
  
  
 
  
  
  
  
  
  
  Example on using
  thread_join( )  
  
  
  
  
  
  
  
  
  
  
  
  
  
   | 
   Consider the following
    program where
    main( ) does
    
    not
    join with the
    worker thread:
 
 | 
void *worker( )
{
    for (int i = 0; i < 10; i++)
    {
        for (int j = 0; j < 10000000; j++);   // Slow thread down...
        printf("*");
        fflush(stdout);
    }
}
int main(int argc, char *argv[])
{   
    pthread_t tid;
    if ( pthread_create(&tid, NULL, worker, NULL) != 0 )  // Create thread
    {
        perror("pthread_create");  // Print error message
        exit(1);
    }
    // Do NOT join (wait)
}    |  
 Result:
      
      nothing is
      printed
      (because 
 main( )
  exited before
  worker
  prints)
   | 
  
  
  
  
  
  DEMO:
  
  demo/pthread/join01.c
  
  
  
  
  
 
  
  
  
  
  
  
  Example on using
  thread_join( )  
  
  
  
  
  
  
  
  
  
  
  
  
  
   | 
   We change it so
 main( ) will
 pthread_join( ) with the
 worker thread:
 
 | 
void *worker( )
{
    for (int i = 0; i < 10; i++)
    {
        for (int j = 0; j < 10000000; j++);   // Slow thread down...
        printf("*");
        fflush(stdout);
    }
}
int main(int argc, char *argv[])
{   
    pthread_t tid;
    if ( pthread_create(&tid, NULL, worker, NULL) != 0 )  // Create thread
    {
        perror("pthread_create");  // Print error message
        exit(1);
    }
    pthread_join(&tid, NULL); // Join with (wait for) worker to finish
}    |  
 Result:
      
      ********** is
      printed
      (because 
 main( )
  waited for
  worker( )
  exit)
   | 
  
  
  
  
  
  DEMO:
  
  demo/pthread/join01b.c
  
  
  
  
  
 
  
  
  
  
  
  
  How to wait for
   multiple worker threads
   to complete execution
  
  
  
  
  
  
  
  
  
  
  
  
  
   | 
   Program that
       creates a
       group of
       worker
       threads:
 
 | 
void *worker(int *id)  // Not syntactically correct, but easier to code...
{
    for (int i = 0; i < 10; i++)
    {
        for (int j = 0; j < 10000000; j++);   // Slow thread down...
        printf("%d", *id);
    }
}
int main(int argc, char *argv[])
{
    pthread_t tid[4];
    int arg[4];
    for ( int i = 0; i < 4; i++ )
    {
        arg[i] = i;
        if ( pthread_create(&tid[i], NULL, worker, &arg[i]) != 0 ){
            perror("pthread_create");  // Print error message
            exit(1);
        }
    }
    for ( int i = 0; i < 4; i++ )
        pthread_join(tid[i], NULL);
} |  
   | 
  
  
  
  
  
  
  
  
  
  
 
  
  
  
  
  
  
  How to wait for
   multiple worker threads
   to complete execution
  
  
  
  
  
  
  
  
  
  
  
  
  
   | 
   
    Create the
      group of
      threads and
      
   save each
      
      thread ID:
 
 | 
void *worker(int *id)  // Not syntactically correct, but easier to code...
{
    for (int i = 0; i < 10; i++)
    {
        for (int j = 0; j < 10000000; j++);   // Slow thread down...
        printf("%d", *id);
    }
}
int main(int argc, char *argv[])
{
    pthread_t tid[4];
    int arg[4];
    for ( int i = 0; i < 4; i++ )
    {
        arg[i] = i;
        if ( pthread_create(&tid[i], NULL, worker, &arg[i]) != 0 ){
            perror("pthread_create");  // Print error message
            exit(1);
        }
    }
    for ( int i = 0; i < 4; i++ )
        pthread_join(tid[i], NULL);
} |  
   | 
  
  
  
  
  
  
  
  
  
  
 
  
  
  
  
  
  
  How to wait for
   multiple worker threads
   to complete execution
  
  
  
  
  
  
  
  
  
  
  
  
  
   | 
   
    Wait for
      every
      thread to
      
   finish:
 
 | 
void *worker(int *id)  // Not syntactically correct, but easier to code...
{
    for (int i = 0; i < 10; i++)
    {
        for (int j = 0; j < 10000000; j++);   // Slow thread down...
        printf("%d", *id);
    }
}
int main(int argc, char *argv[])
{
    pthread_t tid[4];
    int arg[4];
    for ( int i = 0; i < 4; i++ )
    {
        arg[i] = i;
        if ( pthread_create(&tid[i], NULL, worker, &arg[i]) != 0 ){
            perror("pthread_create");  // Print error message
            exit(1);
        }
    }
    for ( int i = 0; i < 4; i++ )
        pthread_join(tid[i], NULL);
} |  
   | 
  
  
  
  
  
  DEMO:
  
  demo/pthread/join02.c
  
  
  
  
  
 
  
  
  
  
  
  
  
  
 
 
  
  
       ❮
  
       ❯