(NOTE: the inter-connection network is irrelevant to the programming and has been omitted).
This detail will be improtant when we have multi-threaded execution of the same program.
In other words: a thread makes progress in executing a program |
These are called SINGLE threaded programs
We will soon see MULTI threaded programs
There is at least one thread within every process (otherwise, the process will not run :-))
A single threaded process has exactly one thread...
In other words:
|
Effect:
|
|
#include <pthread.h> pthread_t tid[100]; // Each thread executes the following function: void *worker(void *arg) { int i; i = pthread_self(); cout << "Hello, I am thread # " << i << endl; return(NULL); /* Thread exits (dies) */ } /* ======================= MAIN ======================= */ int main(int argc, char *argv[]) { int i, num_threads; num_threads = atoi(argv[1]); /* ------ Create threads ------ */ for (i = 0; i < num_threads; i = i + 1) { if ( pthread_create(&tid[i], NULL, worker, NULL) ) { cout << "Cannot create thread" << endl; exit(1); } } // Wait for all threads to terminate for (i = 0; i < num_threads; i = i + 1) pthread_join(tid[i], NULL); exit(0); } |
Compile with: g++ -pthread thread01.C (linux)
Run the program several times and you will notice that the threads prints things out in different order...
We do not have control on when each thread is run....
WRONG...
Huh ? Why not ? What's the problem ?
#include <pthread.h> int N; pthread_t tid[100]; // Each thread executes the following function: void *worker(void *arg) { int i, k, s; for (i = 0; i < 10000; i = i + 1) { N = N + 1; } cout << "Added 10000 to N" << endl; return(NULL); /* Thread exits (dies) */ } /* ======================= MAIN ======================= */ int main(int argc, char *argv[]) { int i, num_threads; num_threads = atoi(argv[1]); /* ------ Create threads ------ */ for (i = 0; i < num_threads; i = i + 1) { if ( pthread_create(&tid[i], NULL, worker, NULL) ) { cout << "Cannot create thread" << endl; exit(1); } } N = 0; // Wait for all threads to terminate for (i = 0; i < num_threads; i = i + 1) pthread_join(tid[i], NULL); cout << "N = " << N << endl << endl; exit(0); } |
Threads that are ready to run will be executed in no particular order by the computer system (the programmer does not have (nor need) control over the therad scheduling --- you could do some thead scheduling, but it is not worth the effort)
Since variables are stored in memory, this method of communication is also known as shared memory
Thread 1 on Thread 2 on Memory CPU 1 CPU 2 ============== =================== ================= N = 1234 Read N --> 1234 Add 1 --> 1235 Read N --> 1234 N = 1235 Write N Add 1 --> 1235 N = 1235 Write N |
void *worker(void *arg) { int N; int i; // Local (non-shared) variable N = 0; for (i = 0; i < 10000; i = i + 1) { N = N + 1; } cout << N; return(NULL); /* Thread exits (dies) */ } |
int i; // Global (SHARED !!!) variable void *worker(void *arg) { int N; N = 0; for (i = 0; i < 10000; i = i + 1) { N = N + 1; } cout << N; return(NULL); /* Thread exits (dies) */ } |