Finding the minimum value in an array

  • Problem description:

    • Given an array of double typed values in x[0 .. (MAX-1)]

    • Find the minimum value stored in the array x[0 .. (MAX-1)]

  • Solution using N worker threads:

    1. Split the array x[0 .. (MAX-1)] into N equal segments

    2. The main thread spawns k worker threads and.... (see (4))

    3. Worker thread k performs:

      • Finds the minimum in segment k of the array

      • Save the minimum found in variable Tmin[k]

    4. The main thread waits for all threads to complete

    5. Then:   find the overall minimum in the Tmin[ ] outputs

Finding the minimum value in an array

  • How to split the array into N equal segments:

  • Work load distribution for a specific thread s:

      Let   n = MAX/N   (MAX = # array elements, N = #threads)
    
      Thread 0:   finds minimum over    x[ 0]     .. x[ n-1]
      Thread 1:   finds minimum over    x[ n]     .. x[2n-1]
      ...
      Thread s:   finds minimum over    x[(s)n]   .. x[(s+1)n-1]
      ...
      Thread N-1: finds minimum over    x[(N-1)n] .. x[MAX]
    

The main( ) function

  • The main( ) function in psuedo code:

    
    
    
    int main(int argc, char *argv[])
    {
       1. Prepare the input array x[MAX]
    
       2. Create N threads with:
    
              for (i = 0; i < N; i = i + 1)
              {
                 id[i] = i;       // Pass id to worker thread
                 pthread_create(&tid[i], NULL, worker, &id[i]) );
              }
    
          Thread i will saved the min of its segment in Tmin[i]
    
       3. Wait for all threads to finish
    
       4. Find min in Tmin[ ] array
    
    
    
    }
    

How the main( ) function generate a sample input numbers

  • (1) The input x[MAX] is generated randomly:

    #define MAX  100000000
    double  x[MAX];                  // Input numbers
    
    int main(int argc, char *argv[])
    {
       1. Prepare the input array x[MAX] 
    
       /* -----------------------------
          Generate MAX random numbers
          ----------------------------- */
       srandom(4444444);
    
       for (i = 0; i < MAX; i++)
       {
          x[i] = random()/(double)1000;
       }
    
    
    
    
    
    
    
    }
    

How the main( ) function create the worker threads

  • (2) The worker threads are created using an id argument - thread i will receive id = i:

    
    
    
    int main(int argc, char *argv[])
    {
       2. Create N threads       
    
       pthread_t tid[100];  // Thread ID of each thread (for pthread_join)
       int    id[100];      // id[i] = index of worker thread i
    
       /* ----------------
          Create threads
          ---------------- */
       for (i = 0; i < N; i++)
       {
          id[i] = i;   // Thread i will get id = i
    
          if ( pthread_create(&tid[i], NULL, worker, &id[i]) )
          {
             perror("pthread_create");
             exit(1);
          }
       }
    }
    

How the main( ) function wait for the worker threads to finish

  • (3) The main() waits for the worker threads to finish with pthread_join():

    double Tmin[100];  // Tmin[i] = min found by thread i
    
    
    int main(int argc, char *argv[])
    {
       3. Wait for all threads to finish       
    
       pthread_t tid[100];  // Thread ID of each thread (for pthread_join)
    
    
       /* ---------------------------------------
          Wait for all worker threads to finish
          --------------------------------------- */
       for (i = 0; i < N; i++)
       {
          pthread_join(tid[i], NULL);
       }
    
    
       // When thread i is finished, thread i would have
       // put its min value in Tmin[i]
     
     
    }
    

How the main( ) function wait for the worker threads to finish

  • (4) Finally, the main() function computes the overall minimum using the Tmin[ ] values:

    double Tmin[100];  // Tmin[i] = min found by thread i
    
    
    int main(int argc, char *argv[])
    {
       4. Find the min in the Tmin[ ] array       
    
       double my_min;
    
    
       /* ---------------------------------------
          Find the minimum in the Tmin[ ] array
          --------------------------------------- */
       my_min = Tmin[0];
    
       for (i = 1; i < N; i++)
       {
          if ( Tmin[i] < my_min )
             my_min = Tmin[i];
    
       }
    
       printf("Min = %lf\n", my_min);  // Print out the min
    }
    

The worker( ) function

  • The worker( ) has the parameter id which identifies the segment that the thread must process:

    void *worker(int *id)   // *id = identifies the segment s below
    {
       int n, start, stop;
       double my_min;
       
       int s = *id;                 // *id = 0, 1, 2, ...or (N-1)
       n = MAX/N;
       
       start = s * n;                               // Start index
       stop = ( (start+n < MAX) ? start+n : MAX );  // Stop index
    
    
       Input x[ ]:
       
          +---+---+---+-- ..... --+---+---+
          |   |   |   |           |   |   |
          +---+---+---+-- ..... --+---+---+
                        ^        ^            
                        |        |
               start = s*n     (s+1)n-1
    }

The worker( ) function

  • Copy the argument *id into the variable s (more convenient):

    void *worker(int *id)   // *id = identifies the segment s below
    {
       int n, start, stop;
       double my_min;
       
       int s = *id;  // s = one of: 0, 1, 2, ...or (N-1)
       n = MAX/N;
       
       start = s * n;                               // Start index
       stop = ( (start+n < MAX) ? start+n : MAX );  // Stop index
    
    
       Input x[ ]:
       
          +---+---+---+-- ..... --+---+---+
          |   |   |   |           |   |   |
          +---+---+---+-- ..... --+---+---+
                        ^        ^            
                        |        |
               start = s*n     (s+1)n-1
    }

Find the start index for the worker( ) function

  • Find the start index of the segment for thread s:

    void *worker(int *id)   // *id = identifies the segment s below
    {
       int n, start, stop;
       double my_min;
       
       int s = *id;  // s = one of: 0, 1, 2, ...or (N-1)
    
       n = MAX/N;               // n = size of 1 segment
       start = s * n;           // Start index
       stop = ( (start+n < MAX) ? start+n : MAX );  // Stop index
    
    
       Input x[ ]:
       
          +---+---+---+-- ..... --+---+---+
          |   |   |   |           |   |   |
          +---+---+---+-- ..... --+---+---+
                        ^        ^            
                        |        |
               start = s*n     (s+1)n-1
    }

Find the stop index for the worker( ) function

  • Find the stop index of the segment for thread s:

    void *worker(int *id)   // *id = identifies the segment s below
    {
       int n, start, stop;
       double my_min;
       
       int s = *id;  // s = one of: 0, 1, 2, ...or (N-1)
    
       n = MAX/N;               // n = size of 1 segment
       start = s * n;           // Start index
       stop = ( (start+n < MAX) ? start+n : MAX );  // Stop index
    
    
       Input x[ ]:
       
          +---+---+---+-- ..... --+---+---+
          |   |   |   |           |   |   |
          +---+---+---+-- ..... --+---+---+
                        ^        ^            
                        |        |
               start = s*n     (s+1)n-1
    }

Find the stop index for the worker( ) function

  • Find the minimum value in the segment:

    void *worker(int *id)   // *id = identifies the segment s below
    {
       int n, start, stop;
       double my_min;
       
       int s = *id;  // s = one of: 0, 1, 2, ...or (N-1)
    
       n = MAX/N;               // n = size of 1 segment
       start = s * n;           // Start index
       stop = ( (start+n < MAX) ? start+n : MAX );  // Stop index
    
       my_min = x[start];           // Initial value for the min
    
       for (int i = start+1; i < stop; i++ )
          if ( x[i] < my_min )
             my_min = x[i];
    
     
    
     
    }

Wrapping up the worker( ) function

  • Save the minimum value in Tmin[s] and exit:

    void *worker(int *id)   // *id = identifies the segment s below
    {
       int n, start, stop;
       double my_min;
       
       int s = *id;  // s = one of: 0, 1, 2, ...or (N-1)
    
       n = MAX/N;               // n = size of 1 segment
       start = s * n;           // Start index
       stop = ( (start+n < MAX) ? start+n : MAX );  // Stop index
    
       my_min = x[start];           // Initial value for the min
    
       for (int i = start+1; i < stop; i++ )
          if ( x[i] < my_min )
             my_min = x[i];
    
       Tmin[s] = my_min;            // Save result in Tmin[s]
    
       pthread_exit(NULL);          // Thread exits 
    }

DEMO: demo/pthread/min-mt1.c (use euler to demo, use 14 threads...)