<< Chapter < Page | Chapter >> Page > |
We can explore this effect by substituting the following
SpinFunc( )
function, replacing
TestFunc( )
function in the
pthread_create( )
call in the previous example:
void *SpinFunc(void *parm) {
int me;me = (int) parm;
printf("SpinFunc me=%d - sleeping %d seconds ...\n", me, me+1);sleep(me+1);
printf("SpinFunc me=%d – wake globvar=%d...\n", me, globvar);globvar ++;
printf("SpinFunc me=%d - spinning globvar=%d...\n", me, globvar);while(globvar<THREAD_COUNT ) ;
printf("SpinFunc me=%d – done globvar=%d...\n", me, globvar);sleep(THREAD_COUNT+1);
}
If you look at the function, each thread entering this function prints a message and goes to sleep for 1, 2, and 3 seconds. Then the function increments
globvar
(initially set to 0 in main) and begins a while-loop, continuously checking the value of
globvar.
As time passes, the second and third threads should finish their
sleep( )
, increment the value for
globvar
, and begin the while-loop. When the last thread reaches the loop, the value for
globvar
is 3 and all the threads exit the loop. However, this isn’t what happens:
recs % create2&[1]23921
recs %Main - globvar=0
Main - creating i=0 tid=4 retval=0Main - creating i=1 tid=5 retval=0
Main - creating i=2 tid=6 retval=0Main thread - threads started globvar=0
Main - waiting for join 4SpinFunc me=0 - sleeping 1 seconds ...
SpinFunc me=1 - sleeping 2 seconds ...SpinFunc me=2 - sleeping 3 seconds ...
SpinFunc me=0 - wake globvar=0...SpinFunc me=0 - spinning globvar=1...recs % ps
PID TTY TIME CMD23921 pts/35 0:09 create2
recs % psPID TTY TIME CMD
23921 pts/35 1:16 create2recs % kill -9 23921
[1]Killed create2
recs %
We run the program in the background
Because we know it will hang and ignore interrupts. and everything seems to run fine. All the threads go to sleep for 1, 2, and 3 seconds. The first thread wakes up and starts the loop waiting for
globvar
to be incremented by the other threads. Unfortunately, with user space threads, there is no automatic time sharing. Because we are in a CPU loop that never makes a system call, the second and third threads never get scheduled so they can complete their
sleep( )
call. To fix this problem, we need to make the following change to the code:
while(globvar<THREAD_COUNT ) sleep(1) ;
With this sleep
Some thread libraries support a call to a routine sched_yield( ) that checks for runnable threads. If it finds a runnable thread, it runs the thread. If no thread is runnable, it returns immediately to the calling thread. This routine allows a thread that has the CPU to ensure that other threads make progress during CPU-intensive periods of its code. call, Threads 2 and 3 get a chance to be “scheduled.” They then finish their sleep calls, increment the
globvar
variable, and the program terminates properly.
You might ask the question, “Then what is the point of user space threads?” Well, when there is a high performance database server or Internet server, the multiple logical threads can overlap network I/O with database I/O and other background computations. This technique is not so useful when the threads all want to perform simultaneous CPU-intensive computations. To do this, you need threads that are created, managed, and scheduled by the operating system rather than a user library.
Notification Switch
Would you like to follow the 'High performance computing' conversation and receive update notifications?