void *worker (void *arg) { .... (You will need to convert arg to the correct type before you can use the value passed) .... } int main(int argc, char *argv[]) { // SEQUENTIAL Section .... Prepare problem (setup shared variables) .... // PARALLEL Section // Start the worker threads for (i = 0; i < NUM_PROCESSORS; i = i + 1) { param[i] = ....; pthread_create(&tid[i], &attr, worker, & param[i]) } // Wait for all workers to finish for (i = 0; i < NUM_PROCESSORS; i = i + 1) pthread_join(tid[i], NULL); // SEQUENTIAL Section .... Post process results from workers.... (Or start another prepare section followed by a parallel + join section) } |
Note:
|
|
|
because:
You will see in the demo programs that the data that need to be processed are stored in a global variabel
You do this, so that:
|
|
(And sometimes, it is not possible to divide the task into non-overlapping tasks and you may have to repeat some steps - necessary evil in parallel programming...
Some ways are better than others.
Pictorially:
values handled by values handled by thread 0 thread 1 |<--------------------->|<--------------------->| | | | | V V min[0] min[1] \ / \ / \ / \ / \ / main thread | | V Actual minimum |
In general, the division of the data in the array is as follows
Main Thread:
|
C++ code for the main( ) function:
/* Shared Variables */ double x[1000000]; // Must be SHARED (accessed by worker threads !!) int start[100]; // Contain starting array index of each thread double min[100]; // Contain the minimum found by each thread int num_threads; // ----------------------------------- // Create worker threads.... // ----------------------------------- for (i = 0; i < num_threads; i = i + 1) { start[i] = i; // Pass ID to thread in a private variable if ( pthread_create(&tid[i], NULL, worker, (void *)&start[i]) ) { cout << "Cannot create thread" << endl; exit(1); } } // ----------------------------------- // Wait for worker threads to end.... // ----------------------------------- for (i = 0; i < num_threads; i = i + 1) pthread_join(tid[i], NULL); // ---------------------------------------- // Post processing: Find actual minimum // ---------------------------------------- my_min = min[0]; for (i = 1; i < num_threads; i++) if ( min[i] < my_min ) my_min = min[i]; |
Worker Thread:
|
The C++ code for worker( ):
void *worker(void *arg) { int i, s; int n, start, stop; double my_min; n = MAX/num_threads; // number of elements to handle s = * (int *) arg; // Convert arg to an integer start = s * n; // Starting index if ( s != (num_threads-1) ) { stop = start + n; // Ending index } else { stop = MAX; } my_min = x[start]; for (i = start+1; i < stop; i++ ) // Find min in my range { if ( x[i] < my_min ) my_min = x[i]; } min[s] = my_min; // Store min in private slot return(NULL); /* Thread exits (dies) */ } |
On Solaris compile with: CC -mt min-mt1.C
On Linux compile with: g++ -pthread min-mt1.C
Changes that you need to make to compile on Linux:
#include <iostream.h> ===> #include <iostream> Add line: using namespace std;
Pictorially:
values handled by thread 0 | | | | | | | | | | | | | | V V V V V V V V V V V V V V |-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-| ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ | | | | | | | | | | | | | | values handled by thread 1 Thread 0 Thread 1 | | | | V V min[0] min[1] \ / \ / \ / \ / \ / main thread | | V Actual minimum |
Main Thread: (UNCHANGED)
// ----------------------------------- // Create worker threads.... // ----------------------------------- for (i = 0; i < num_threads; i = i + 1) { start[i] = i; // Pass ID to thread in a private variable if ( pthread_create(&tid[i], NULL, worker, (void *)&start[i]) ) { cout << "Cannot create thread" << endl; exit(1); } } // ----------------------------------- // Wait for worker threads to end.... // ----------------------------------- for (i = 0; i < num_threads; i = i + 1) pthread_join(tid[i], NULL); // ---------------------------------------- // Post processing: Find actual minimum // ---------------------------------------- my_min = min[0]; for (i = 1; i < num_threads; i++) if ( min[i] < my_min ) my_min = min[i]; |
Worker Thread: (CHANGED !!!)
void *worker(void *arg) { int i, s; double my_min; s = * (int *) arg; // Convert arg to an integer // -------------------------------------- // Find min in my range // -------------------------------------- my_min = x[s]; for (i = s+num_threads; i < MAX; i += num_threads) { if ( x[i] < my_min ) my_min = x[i]; }min[s] = my_min; // Store min in private slot return(NULL); /* Thread exits (dies) */ } |
See the elements processed by the thread s:
It's much easier to code the worker thread !!!
Compile with: g++ -pthread min-mt2.C
But the second version... no so much...
Each thread traverse the array from the beginning until the end.
Due to the large size of the array, the whole array cannot be stored in memory and will be paged in when a thread access the desired array elements.
(Solution 1 does not have the page problem, because the array element access pattern is "limited" to a tightly coupled region of the array)