![Page 1: (p)Threads Libraries Math 442 es Jim Fix. Life cycle of a thread](https://reader035.vdocuments.site/reader035/viewer/2022081519/56649f575503460f94c7cb63/html5/thumbnails/1.jpg)
(p)Threads Libraries
Math 442 es
Jim Fix
![Page 2: (p)Threads Libraries Math 442 es Jim Fix. Life cycle of a thread](https://reader035.vdocuments.site/reader035/viewer/2022081519/56649f575503460f94c7cb63/html5/thumbnails/2.jpg)
Life cycle of a thread
![Page 3: (p)Threads Libraries Math 442 es Jim Fix. Life cycle of a thread](https://reader035.vdocuments.site/reader035/viewer/2022081519/56649f575503460f94c7cb63/html5/thumbnails/3.jpg)
Creation/Joining/Exit
When a process is first created, it has one thread of execution.
(C) executes main
That thread spawns other threads(pthread) specify initial code for new thread
Each, in turn, can spawn more threads
Any thread can wait for a specified thread to ``join” it
(pthread) blocks until other other thread terminates
![Page 4: (p)Threads Libraries Math 442 es Jim Fix. Life cycle of a thread](https://reader035.vdocuments.site/reader035/viewer/2022081519/56649f575503460f94c7cb63/html5/thumbnails/4.jpg)
Using libpthread.a: creation
Creating a thread (in Terminal:``man pthread_create”):int pthread_create(pthread_t *thread, pthread_attr_t *attr, void *(*start_routine)(void *), void *arg);
thread: reference to a thread descriptor; will get filled with new thread’s info
attr: reference to a thread attribute struct
start_routine: proc that new thread executes
arg: parameter for that start routine
![Page 5: (p)Threads Libraries Math 442 es Jim Fix. Life cycle of a thread](https://reader035.vdocuments.site/reader035/viewer/2022081519/56649f575503460f94c7cb63/html5/thumbnails/5.jpg)
Using libpthread.a: join/exit
To wait for a another thread to terminate:int pthread_join(pthread_t *other_thread, void **value_h);
other_thread: descriptor of thread to wait for
ret_value: handle to value returned by other thread
Other thread joins this join-caller when:
• it calls int pthread_exit(void *value_p)
• it returns (a value) from its start routine
![Page 6: (p)Threads Libraries Math 442 es Jim Fix. Life cycle of a thread](https://reader035.vdocuments.site/reader035/viewer/2022081519/56649f575503460f94c7cb63/html5/thumbnails/6.jpg)
Simple example: patrub.clong pat() { for (long i=0; i<1000000L; i++)
printf("pat #%d\n",i); return i; }long rub() { for (long i=0; i<1000000L; i++) printf("rub #%d\n",i); } return i; }int main(int argc, char **argv) { pthread_t id1, id2; long val1, val2;pthread_attr_t a;pthread_attr_init(&a);pthread_create(&id1,&a,(void *(*)(void *))(&pat),NULL); pthread_create(&id2,&a,(void *(*)(void *))(&rub),NULL);pthread_join(id1,(void **)&val1); pthread_join(id2,(void **)&val2); printf("Completed pats: %d ...rubs:%d\n",val1,val2); pthread_exit(NULL);}
other_thread: descriptor of thread to wait for
ret_value: handle to value returned by other thread
Other thread joins this join-caller when:
• it calls int pthread_exit(void *value_p)
• it returns (a value) from its start routine
![Page 7: (p)Threads Libraries Math 442 es Jim Fix. Life cycle of a thread](https://reader035.vdocuments.site/reader035/viewer/2022081519/56649f575503460f94c7cb63/html5/thumbnails/7.jpg)
The Trouble w/ Concurrency
Suppose one thread executes this code:1. void count1(int *c) {2. while (1) {3. (*c) = (*c) + 1;4. }5. }
...and another executes this code:1. void count2(int *c) {2. while (1) {3. (*c) = (*c) + 1;4. }5. }... and the main driving code looks like this:
static int shared_counter = 0;...{... pthread_create(&id1,NULL,&count1,&shared_counter); pthread_create(&id2,NULL,&count2,&shared_counter); ...}
What can go wrong?
![Page 8: (p)Threads Libraries Math 442 es Jim Fix. Life cycle of a thread](https://reader035.vdocuments.site/reader035/viewer/2022081519/56649f575503460f94c7cb63/html5/thumbnails/8.jpg)
What’s Really Happening
The code:...(*c) = (*c) + 1;...
...is really code like:mov r28,r24mov r29,r25...ld r18,Yldd r19,Y+1subi r18,lo8(-1)sbci r19,hi8(-1)st r18,Ystd r19,Y+1...
...
The increment op is not an ``atomic” one.
When two threads run concurrently, say, (even) on a single processor (with preemption), their execution could be interleaved.
![Page 9: (p)Threads Libraries Math 442 es Jim Fix. Life cycle of a thread](https://reader035.vdocuments.site/reader035/viewer/2022081519/56649f575503460f94c7cb63/html5/thumbnails/9.jpg)
One Possible Interleavingld r18,Yldd r19,Y+1subi r18,lo8(-1)sbci r19,hi8(-1)st r18,Ystd r19,Y+1ld r18,Yldd r19,Y+1subi r18,lo8(-1)sbci r19,hi8(-1)st r18,Ystd r19,Y+1ld r18,Yldd r19,Y+1subi r18,lo8(-1)sbci r19,hi8(-1)st r18,Ystd r19,Y+1ld r18,Yldd r19,Y+1subi r18,lo8(-1)sbci r19,hi8(-1)st r18,Ystd r19,Y+1ld r18,Yldd r19,Y+1subi r18,lo8(-1)sbci r19,hi8(-1)
mov.w @r0,r1adds #1,r1mov.w r1,@r0
thread 1
thread 2
![Page 10: (p)Threads Libraries Math 442 es Jim Fix. Life cycle of a thread](https://reader035.vdocuments.site/reader035/viewer/2022081519/56649f575503460f94c7cb63/html5/thumbnails/10.jpg)
An Different Interleavingld r18,Yldd r19,Y+1ld r18,Yldd r19,Y+1subi r18,lo8(-1)sbci r19,hi8(-1)st r18,Ystd r19,Y+1ld r18,Yldd r19,Y+1subi r18,lo8(-1)sbci r19,hi8(-1)st r18,Ystd r19,Y+1 subi r18,lo8(-1)sbci r19,hi8(-1)st r18,Ystd r19,Y+1ld r18,Yldd r19,Y+1subi r18,lo8(-1)sbci r19,hi8(-1)st r18,Ystd r19,Y+1
What happens? (remember: registers are unshared)
thread 1
thread 2
![Page 11: (p)Threads Libraries Math 442 es Jim Fix. Life cycle of a thread](https://reader035.vdocuments.site/reader035/viewer/2022081519/56649f575503460f94c7cb63/html5/thumbnails/11.jpg)
A test: counters.c (part I)
The main driver:1. int main(int argc, char **argv) {2. long counter = 0;3. pthread_t id1, id2;4. long rv1, rv2;5. pthread_attr_t a; pthread_attr_init(&a);6. pthread_create(&id1,&a,(void *(*)(void *))(&count),7. (void *)&counter);8. pthread_create(&id2,&a,(void *(*)(void *))(&count),9. (void *)&counter);10. pthread_join(id1,(void **)&val1); 11. pthread_join(id2,(void **)&val2);12. printf("%d + %d = %d?\n",val1,val2,counter);13. return 0;14. }
![Page 12: (p)Threads Libraries Math 442 es Jim Fix. Life cycle of a thread](https://reader035.vdocuments.site/reader035/viewer/2022081519/56649f575503460f94c7cb63/html5/thumbnails/12.jpg)
A test: counters.c (part II)
Each counter thread’s code:1. long count(long *c) {2. long i;3. for (i=0; i<1000000L; i++) {4. int j = (*c);5. (*c) = j+1;6. }7. return i;8. }
Let’s run it and see ( go to Terminal )
![Page 13: (p)Threads Libraries Math 442 es Jim Fix. Life cycle of a thread](https://reader035.vdocuments.site/reader035/viewer/2022081519/56649f575503460f94c7cb63/html5/thumbnails/13.jpg)
Increment is a critical section of the code:
long i; for (i=0; i<1000000L; i++) { int j = (*c); (*c) = j+1; } return i;
The counter is shared by both threads.• When they increment, they should
have exclusive access to it.• }
The Problem
![Page 14: (p)Threads Libraries Math 442 es Jim Fix. Life cycle of a thread](https://reader035.vdocuments.site/reader035/viewer/2022081519/56649f575503460f94c7cb63/html5/thumbnails/14.jpg)
MutexesMost thread libraries (including POSIX) provide mutex variables for locking critical sections:pthread_mutex_t m;pthread_mutexattr_t m_attr;
pthread_mutex_init(&m,&m_attr);// initializes a mutex variable
pthread_mutex_lock(&m);// gives access to m, other threads block or wait.
pthread_mutex_unlock(&m);// releases m, gives to a waiting thread.
The mutex variable provides mutual exclusion.
![Page 15: (p)Threads Libraries Math 442 es Jim Fix. Life cycle of a thread](https://reader035.vdocuments.site/reader035/viewer/2022081519/56649f575503460f94c7cb63/html5/thumbnails/15.jpg)
Locking a Crit. Sect.Here is the new version of the counter code:1. long count(counter_m *cm) {2. long *c = cm->counter;3. pthread_mutex_t *m = cm->mutex;4. long i;5. for (i=0; i<1000000L; i++) {6. pthread_mutex_lock(m); // acquire the lock7. int j = (*c);8. (*c) = j+1;9. pthread_mutex_unlock(m); // release the lock10. }11. return i;12. }
Let’s run it. (go to Terminal)
![Page 16: (p)Threads Libraries Math 442 es Jim Fix. Life cycle of a thread](https://reader035.vdocuments.site/reader035/viewer/2022081519/56649f575503460f94c7cb63/html5/thumbnails/16.jpg)
A question for your consideration:
How does one build a mutex????
(i.e. a mutex library for a threading system????)
![Page 17: (p)Threads Libraries Math 442 es Jim Fix. Life cycle of a thread](https://reader035.vdocuments.site/reader035/viewer/2022081519/56649f575503460f94c7cb63/html5/thumbnails/17.jpg)
Thread SynchronizationSynchronizing concurrent threads’ access to shared data/resources is crucial.
See: (thanks to UCB’s cs16x)space shuttle (Garman, 1981)
Therac-25 (Leveson, 1995)