Download presentation
Presentation is loading. Please wait.
Published byLee Jenkins Modified over 9 years ago
1
(p)Threads Libraries Math 442 es Jim Fix
2
Life cycle of a thread
3
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
4
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
5
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
6
Simple example: patrub.c long 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
7
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?
8
What’s Really Happening The code: 1.... 2.(*c) = (*c) + 1; 3.......is really code like: 1.mov r28,r24 2.mov r29,r25 3.... 4.ld r18,Y 5.ldd r19,Y+1 6.subi r18,lo8(-1) 7.sbci r19,hi8(-1) 8.st r18,Y 9.std r19,Y+1 10.... 11.... 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.
9
One Possible Interleaving 1.ld r18,Y 2.ldd r19,Y+1 3.subi r18,lo8(-1) 4.sbci r19,hi8(-1) 5.st r18,Y 6.std r19,Y+1 7.ld r18,Y 8.ldd r19,Y+1 9.subi r18,lo8(-1) 10.sbci r19,hi8(-1) 11.st r18,Y 12.std r19,Y+1 13.ld r18,Y 14.ldd r19,Y+1 15.subi r18,lo8(-1) 16.sbci r19,hi8(-1) 17.st r18,Y 18.std r19,Y+1 19.ld r18,Y 20.ldd r19,Y+1 21.subi r18,lo8(-1) 22.sbci r19,hi8(-1) 23.st r18,Y 24.std r19,Y+1 25.ld r18,Y 26.ldd r19,Y+1 27.subi r18,lo8(-1) 28.sbci r19,hi8(-1) 29.mov.w @r0,r1 30.adds #1,r1 31.mov.w r1,@r0 thread 1 thread 2
10
An Different Interleaving 1.ld r18,Y 2.ldd r19,Y+1 3.ld r18,Y 4.ldd r19,Y+1 5.subi r18,lo8(-1) 6.sbci r19,hi8(-1) 7.st r18,Y 8.std r19,Y+1 9.ld r18,Y 10.ldd r19,Y+1 11.subi r18,lo8(-1) 12.sbci r19,hi8(-1) 13.st r18,Y 14.std r19,Y+1 15.subi r18,lo8(-1) 16.sbci r19,hi8(-1) 17.st r18,Y 18.std r19,Y+1 19.ld r18,Y 20.ldd r19,Y+1 21.subi r18,lo8(-1) 22.sbci r19,hi8(-1) 23.st r18,Y 24.std r19,Y+1 What happens? (remember: registers are unshared) thread 1 thread 2
11
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.}
12
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 )
13
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. 1. } The Problem
14
Mutexes Most thread libraries (including POSIX) provide mutex variables for locking critical sections: 1.pthread_mutex_t m; 2.pthread_mutexattr_t m_attr; 3.pthread_mutex_init(&m,&m_attr); 4.// initializes a mutex variable 5.pthread_mutex_lock(&m); 6.// gives access to m, other threads block or wait. 7.pthread_mutex_unlock(&m); 8.// releases m, gives to a waiting thread. 9.The mutex variable provides mutual exclusion.
15
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 lock 7. int j = (*c); 8. (*c) = j+1; 9. pthread_mutex_unlock(m); // release the lock 10. } 11. return i; 12.} Let’s run it. (go to Terminal)
16
A question for your consideration: How does one build a mutex???? (i.e. a mutex library for a threading system????)
17
Thread Synchronization Synchronizing concurrent threads’ access to shared data/resources is crucial. See: (thanks to UCB’s cs16x) space shuttlespace shuttle (Garman, 1981) Therac-25Therac-25 (Leveson, 1995)
Similar presentations
© 2024 SlidePlayer.com. Inc.
All rights reserved.