Download presentation
Presentation is loading. Please wait.
1
Threads Synchronization
2
POSIX Pthreads For UNIX systems, implementations of threads that adhere to the IEEE POSIX c standard are Pthreads Pthreads are C language programming types defined in the pthread.h header/include file The primary motivation behind Pthreads is improving program performance Can be created with much less OS overhead Needs fewer system resources to run View comparison of forking processes to using a pthreads_create subroutine
3
Threads vs Forks Timings reflect 50,000 processes/thread creations
PLATFORM fork() pthread_create() REAL USER SYSTEM AMD 2.4 GHz Opteron (8cpus/node) 41.07 60.08 9.01 0.66 0.19 0.43 IBM 1.9 GHz POWER5 p5-575 (8cpus/node) 64.24 30.78 27.68 1.75 0.69 1.1 IBM 1.5 GHz POWER4 (8cpus/node) 104.05 48.64 47.21 2.01 1 1.52 INTEL 2.4 GHz Xeon (2 cpus/node) 54.95 1.54 20.78 1.64 0.67 0.9 INTEL 1.4 GHz Itanium2 (4 cpus/node) 54.54 1.07 22.22 2.03 1.26
4
Example declares the various Pthreads
functions, constants, types, etc.
5
Example
6
Example
7
Example gcc −g −Wall −o pth_hello pth_hello . c −lpthread
link in the Pthreads library
8
Example Hello from the main thread Hello from thread 0 of 1
. / pth_hello <number of threads> . / pth_hello 1 Hello from the main thread Hello from thread 0 of 1 . / pth_hello 4 Hello from the main thread Hello from thread 0 of 4 Hello from thread 1 of 4 Hello from thread 2 of 4 Hello from thread 3 of 4
9
Starting a Thread One object for each thread. int pthread_create (
pthread.h One object for each thread. pthread_t int pthread_create ( pthread_t* thread_p /* out */ , const pthread_attr_t* attr_p /* in */ , void* (*start_routine ) ( void ) /* in */ , void* arg_p /* in */ ) ;
10
pthread_t The actual data that they store are system-specific
Their data members aren’t directly accessible to user code However, the Pthreads standard guarantees that a pthread_t object does store enough information to uniquely identify the thread with which it’s associated
11
e.g., stack size (dft 2MB), stack address, scheduling, …
pthread_t int pthread_create ( pthread_t* thread_p /* out */ , const pthread_attr_t* attr_p /* in */ , void* (*start_routine ) ( void ) /* in */ , void* arg_p /* in */ ) ; e.g., stack size (dft 2MB), stack address, scheduling, … We won’t be using, so we just pass NULL. Allocate before calling. The function that the thread is to run. Pointer to the argument that should be passed to the function start_routine.
12
The Function Prototype: void* thread_function ( void* args_p ) ;
Void* can be cast to any pointer type in C So args_p can point to a list containing one or more values needed by thread_function Similarly, the return value of thread_function can point to a list of one or more values
13
pthread_join(pthread_t *thread, void **result);
We call the function pthread_join once for each thread A single call to pthread_join will wait for the thread associated with the pthread_t object to complete pthread_join(pthread_t *thread, void **result); Wait for specified thread to finish. Place exit value into *result
14
Need for Synchronization
In order to write any kind of concurrent program, you must be able to reliably synchronize the different threads Without synchronization, two threads will start to change some data at the same time, one will overwrite the other
15
Need for Synchronization
A critical section is a section of code that must be allowed to complete atomically with no interruption that affects its completion We create critical sections by locking a lock, manipulating the data, then releasing the lock Incrementing a counter or updating a record in a database need to be critical sections
16
Data Race static int s = 0; Thread 0 for i = 0, n/2-1 s = s + f(A[i])
for i = n/2, n-1 s = s + f(A[i]) A race condition or data race occurs when: two processors (or two threads) access the same variable, and at least one does a write The accesses are concurrent (not synchronized) so they could happen simultaneously
17
Data Race All shared data must be protected by locks Examples:
data structures which are passed to other threads global variables
18
Synchronization Synchronization is provided by a set of functions that manipulate special structures in user memory POSIX implements three synchronization variables and the function pthread_join() to provide this functionality There are two basic things you want to do Thing one is that you want to protect shared data. This is what locks do Thing two is that you want to prevent threads from running when there’s nothing for them to do
19
Methods Busy waiting Mutex (lock) Semaphore Conditional Variables
20
Busy Waiting static int s = 0; static int flag=0 Thread 0 Thread 1
int temp, my_rank for i = 0, n/2-1 temp0=f(A[i]) while flag!=my_rank; s = s + temp0 flag= (flag+1) %2 Thread 1 int temp, my_rank for i = n/2, n-1 temp=f(A[i]) while flag!=my_rank; s = s + temp flag= (flag+1) %2 A thread repeatedly tests a condition, but, effectively, does no useful work until the condition has the appropriate value Weakness: Waste CPU resource. Sometime not safe with compiler optimization
21
Mutexes A thread that is busy-waiting may continually use the CPU accomplishing nothing Mutex (mutual exclusion) is a special type of variable that can be used to restrict access to a critical section to a single thread at a time Used to guarantee that one thread “excludes” all other threads while it executes the critical section The Pthreads standard includes a special type for mutexes: pthread_mutex_t.
22
Mutexes Pointer to the mutex
If attr is NULL, the default mutex attributes are used; the effect shall be the same as passing the address of a default mutex attributes object (e.g., normal – no deadlock detection, error checking, recursive, ….)
23
Mutexes When a Pthreads program finishes using a mutex, it should call
In order to gain access to a critical section a thread calls
24
Mutexes When a thread is finished executing the code in a critical section, it should call
25
Mutexes The first thread that locks the mutex gets ownership, and any subsequent attempts to lock it will fail When the owner unlocks it, one of the sleepers will be awakened, made runnable, and given the chance to obtain ownership It is possible that some other thread will call pthread_mutex_lock() and get ownership before the newly awakened thread does
26
Mutexes Thread 1 Thread 2 Acquire mutex lock Critical section
Unlock/Release mutex Acquire mutex lock Critical section Unlock/Release mutex
27
Mutexes
28
Mutexes Because mutexes protect sections of code, it is not legal for one thread to lock a mutex and for another thread to unlock it Depending upon the library implementation, this might not result in a runtime error, but it is illegal
29
Example
30
Semaphores A counting semaphore (aka PV semaphore) is a variable that you can increment arbitrarily high, but decrement only to zero A sem_post() operation (aka “V” –verhogen in Dutch) increments the semaphore, A sem_wait() (aka “P” – Proberen te verlagen) attempts to decrement it If the semaphore is greater than zero, the operation succeeds; if not, then the calling thread must go to sleep until a different thread increments it
31
Semaphores Semaphore S – integer variable - can only be accessed /modified via two (atomic) operations with the following semantics: wait (S) { //also called P() while S <= 0 wait in a queue; S--; } post(S) { //also called V() S++; Wake up a thread that waits in the queue.
32
Semaphores Semaphores are also useful when you want a thread to wait for something You can accomplish this by having the thread call sem_wait() on a semaphore with value zero Then, have another thread increment the semaphore when you’re ready for the thread to continue
33
Semaphores Examples of complex synchronization
Functionality/weakness Busy waiting Spinning for a condition. Waste resource. Not safe Mutex lock Support code with simple mutual exclusion Semaphore Handle more complex signal-based synchronization Examples of complex synchronization Allow a resource to be shared among multiple threads. Mutex: no more than 1 thread for one protected region. Allow a thread waiting for a condition after a signal E.g. Control the access order of threads entering the critical section. For mutexes, the order is left to chance and the system.
34
Semaphores
35
Semaphores Semaphores are not part of Pthreads; you need to add this.
36
Example
37
Readers - Writers A writer do { sem_wait(wrt) ; //semaphore wrt
// writing is performed sem_post(wrt) ; // } while (TRUE);
38
Readers - Writers Reader do { mutex_lock(mutex); readcount ++ ;
if (readcount == 1) sem_wait(wrt); //check if anybody is writing mutex_unlock(mutex) // reading is performed readcount - - ; if (readcount == 0) sem_post(wrt) ; //writing is allowed now nlock(mutex) ; } while (TRUE);
39
Condition Variables Perhaps you want a thread to execute some code only if X > 17 and Y is prime As long as you can express the condition in a program, you can use it in a condition variable A condition variable creates a safe environment for you to test your condition, sleep on it when false, and be awakened when it might have become true
40
Condition Variables It works like this:
A thread obtains a mutex (condition variables always have an associated mutex) and tests the condition under the mutex’s protection No other thread should alter any aspect of the condition without holding the mutex If the condition is true, your thread completes its task, releasing the mutex when appropriate If the condition isn’t true, the mutex is released for you, and your thread goes to sleep on the condition variable
41
Condition Variables When some other thread changes some aspect of the condition, it calls pthread_cond_signal(), waking up one sleeping thread* Your thread then reacquires the mutex, reevaluates the condition, and either succeeds or goes back to sleep, depending upon the outcome Attention: You must reevaluate the condition * the scheduling policy shall determine the order in which threads are unblocked
42
Condition Variables More programming primitives to simplify code for synchronization of threads Synchronization Functionality Busy waiting Spinning for a condition. Waste resource. Not safe Mutex lock Support code with simple mutual exclusion Semaphore Signal-based synchronization. Allow sharing (not wait unless semaphore=0) Condition variables More complex synchronization: Let threads wait until a user-defined condition becomes true
43
Condition Variables int status; pthread_condition_t cond;
const pthread_condattr_t attr; pthread_mutex mutex; status = pthread_cond_init(&cond,&attr); status = pthread_cond_destroy(&cond); status = pthread_cond_wait(&cond,&mutex); -wait in a queue until somebody wakes up. Then the mutex is reacquired. status = pthread_cond_signal(&cond); - wake up one waiting thread. status = pthread_cond_broadcast(&cond); - wake up all waiting threads in that condition
44
Condition Variables Thread 1: //try to get into critical section and wait for the condition Mutex_lock(mutex); While (condition is not satisfied) Cond_Wait(mutex, cond); Critical Section; Mutex_unlock(mutex) Thread 2: // Try to create the condition. When condition can satisfy, Signal(cond); Mutex_unlock(mutex);
45
Condition Variables
46
Producers - Consumers
47
Producers - Consumers int avail=0; // # of data items available for consumption Consumer thread: while (avail <=0); //wait Consume next item; avail = avail-1; Producer thread: Produce next item; avail = avail+1; //notify an item is available
48
Producers - Consumers int avail=0; // # of data items available for consumption Pthread mutex m and condition cond; Consumer thread: multex_lock(&m) while (avail <=0) Cond_Wait(&cond, &m); Consume next item; avail = avail-1; mutex_unlock(&mutex) Producer thread: mutex_lock(&m); Produce next item; availl = avail+1; mutex_unlock(&m); Cond_signal(&cond); //notify an item is available
49
Producers – Consumers Code
We use the mutex requests_lock to protect both length and the list itself, so we move it out of add() and remove()
50
Condition Variables Depending upon your program, you may wish to wake up all the threads that are waiting on a condition A pthread_cond_broadcast() is used exactly like pthread_cond_signal() It is called after some aspect of the condition has changed It then wakes all of the sleeping threads (in an undefined order), which then must all hurry off to reevaluate the condition This may cause some contention for the mutex
51
Problems You could initialize the condition variable to be cross- process, but not the mutex; or vice-versa Don’t do that!
52
Condition Variables Condition variables also allow you to limit the sleep time. By calling pthread_cond_timedwait(), you can arrange to be awakened after a fixed amount of time Should you know the condition ought to change within some time frame, you can wait for that amount of time, then go out and figure out what went wrong Once the wait time expires, the sleeping thread will be moved off the sleep queue and pthread_cond_timedwait() will return ETIMEDOUT Counterwise, once the sleeper is signaled, it is taken off the sleep queue and the timer is turned off
53
Condition Variables If you simply neglect to hold the mutex while testing or changing the value of the condition, your program will be subject to the fearsome lost wakeup problem This is where one of your threads misses a wakeup signal because it had not yet gone to sleep
54
Thank you! Questions??
Similar presentations
© 2025 SlidePlayer.com. Inc.
All rights reserved.