Download presentation
Presentation is loading. Please wait.
1
Waiting and Synchronization
Windows Concurrency Waiting and Synchronization Copyright © 1997 – 2016 Curt Hill
2
Introduction We have previously seen the presentations on threads
We now need to look at the wait functions and other synchronization APIs First we consider race errors You should have previously seen this Then how to combat these With synchronization objects With waits Copyright © 1997 – 2016 Curt Hill
3
Race Example Consider two tasks that share an integer variable share
Task A has share = share + 2; Task B has share = share + 5; Copyright © 1997 – 2016 Curt Hill
4
Racing Form C and Assembly
;share += 2 mov ax,share add ax,2 mov share,ax ;share += 5 mov ax,share add ax,5 mov share,ax There are three possible outcomes Copyright © 1997 – 2016 Curt Hill
5
Race Results If one task completes before the other starts share will have 7 added to it Complete serialization If A starts and is interrupted, then B executes, then the add of two is kept and the add of five is lost If B starts first and is interrupted, then the add of five is kept and the add of two is lost Copyright © 1997 – 2016 Curt Hill
6
Classical Problems There are a number of problems that illustrate race errors The first is the producer and consumer problem One task fills a buffer and another empties it This problem is inside every file copy Consider the Producer and Consumer problem: Copyright © 1997 – 2016 Curt Hill
7
Producer and Consumer Problem
Remove point Add point Length Copyright © 1997 – 2016 Curt Hill
8
Producer/Consumer A buffer exists char buf[80]; int len,strt,end;
A thread adds a char: if(len<80){ end=(end+1)%80; buf[end] = inchar; len=len+1; } A thread empties: if(len>0) { strt = (strt+1)%80; outchar = buf[strt]; len=len-1; } Copyright © 1997 – 2016 Curt Hill
9
Producers and Consumers
The critical thing here is the len variable What happens if they both try to store to that variable at the same time? The assignment statement is not a single machine language statement in all cases Caching only complicates things in a multi CPU system Copyright © 1997 – 2016 Curt Hill
10
Recursion The C family all allow recursion
This is because variables are by default automatic Created when a function is entered and discarded upon exit We are not particularly interested in recursion today but it leads us to a type of function that we are interested in Reentrant Copyright © 1997 – 2016 Curt Hill
11
Reentrant Function A reentrant function allows multiple threads in it while preserving thread-safety Every function in C/C++ is reentrant if it has these characteristics Only uses parameters and local variables No reference/pointer parameters refer to shared variables No variables are static It only calls reentrant functions Copyright © 1997 – 2016 Curt Hill
12
More A reentrant function does not need synchronization
Thus we prefer to call these – they do not slow the threads It is only using things that are on the local thread’s stack There is no sharing Every reentrant function is thread safe but not every thread safe function is reentrant Copyright © 1997 – 2016 Curt Hill
13
Functions and methods Many functions are reentrant just because they do not share anything Good function design prefers use of value parameters and local variables Most methods are not They access instance variables or static variables Copyright © 1997 – 2016 Curt Hill
14
Serialization Any time there is sharing we must be able to serialize threads Prevent two threads from executing code in the same area What we need is to detect that another thread has control and wait the new thread These are available in the hardware A race condition exists if we do not serialize This leads us to the topic of synchronization Copyright © 1997 – 2016 Curt Hill
15
Synchronization Having threads executing without any communication is questionable in most cases Synchronization provides the ability to serialize our threads so that no race errors occur Windows, like any OS, provides several synchronization methods Copyright © 1997 – 2016 Curt Hill
16
Synchronization Items
There are several that are interesting Critical section Semaphores Mutex We may not need to consider all of them We will anyway These are not OO classes but instead structs and standalone methods Makes it easier to err Copyright © 1997 – 2016 Curt Hill
17
One More Recall that Windows was built with C and not C++
It has structs and no classes Another synchronization item is called a monitor It is a class that encapsulates a critical section Thus only one thread can be active in any of its methods Copyright © 1997 – 2016 Curt Hill
18
Critical Section A critical section guards one or more portions of code Only one thread may be executing in any of these pieces at a time If the thread is suspended while inside it still possesses the code Calling subsequent function from within also leaves the thread owning the code These are used in the threader demo Copyright © 1997 – 2016 Curt Hill
19
Critical Section This is the struct: CRITICAL_SECTION
Usually addressed by a long pointer Create with new but initialize with InitializeCriticalSection Parameter is the pointer The functions are: EnterCriticalSection LeaveCriticalSection TryEnterCriticalSection returns TRUE if it was obtained All take the pointer Copyright © 1997 – Curt Hill
20
Signatures void WINAPI InitializeCriticalSection( _Out_ LPCRITICAL_SECTION lpCriticalSection ); void WINAPI EnterCriticalSection( _Inout_ LPCRITICAL_SECTION lpCriticalSection ); void WINAPI LeaveCriticalSection( _Inout_ LPCRITICAL_SECTION lpCriticalSection ); BOOL WINAPI TryEnterCriticalSection( _Inout_ LPCRITICAL_SECTION lpCriticalSection ); Copyright © 1997 – 2016 Curt Hill
21
On Your Honor The four functions and the corresponding control block know nothing about any code Instead they believe that you put an Enter and Leave around code that needs to be serialized This code may in same class or anywhere in the process As long as they all have access to the pointer to the critical section Copyright © 1997 – 2016 Curt Hill
22
Critical Section Guidelines
Keep your critical sections short Long ones reduce concurrency The process should usually provide memory for the struct We do not want a thread to end and destroy the struct Multiple critical sections may be used to protect multiple shared variables One critical section may protect any number of references with the enters/leaves Copyright © 1997 – 2016 Curt Hill
23
Semaphores Named after the flags that pre-radio ships used to communicate Similar to critical sections and mutexs in many ways A semaphore has an arbitrary maximum value of threads that it may allow into a portion of code This is always one for a critical section Only use these if it is acceptable for multiple threads to share code simultaneously Copyright © 1997 – 2016 Curt Hill
24
Signatures HANDLE WINAPI CreateSemaphore( _In_opt_ LPSECURITY_ATTRIBUTES lpSemaphoreAttributes, _In_ LONG lInitialCount, _In_ LONG lMaximumCount, _In_opt_ LPCTSTR lpName ); HANDLE WINAPI OpenSemaphore( _In_ DWORD dwDesiredAccess, _In_ BOOL bInheritHandle, _In_ LPCTSTR lpName ); BOOL WINAPI ReleaseSemaphore( _In_ HANDLE hSemaphore, _In_ LONG lReleaseCount, _Out_opt_ LPLONG lpPreviousCount ); Copyright © 1997 – 2016 Curt Hill
25
Usage The main process will create the semaphore
It specifies the maximum count and the current count An Open checks the count If there is more capacity it increments the count Otherwise it waits until a thread leaves Release decrements the count It releases the semaphore Copyright © 1997 – 2016 Curt Hill
26
Waiting Waiting is something that most threads do
They wait for another task to complete something Waiting can be of two forms: Busy waiting AKA polling, spinning on a loop Wastes CPU time - undesirable One of several OS wait calls Removes the thread from the ready queue until an event happens Copyright © 1997 – 2016 Curt Hill
27
OS Waiting When waiting we must always wait for an event to happen
This event may be one of several things A timer fires An external action occurs A process/thread completes some action A combination of several of these More on these a little later Copyright © 1997 – 2016 Curt Hill
28
Sleep Suspends the thread for a number of milliseconds Sets a timer
Uses the timer event to resume Signature: VOID WINAPI Sleep( _In_ DWORD dwMilliseconds); May be used in a good polling routine where there is nothing that passes for an event available Also frequently used in animation Copyright © 1997 – 2016 Curt Hill
29
Sleep Example … while (OK) { if(var != oldvar) { process_var(var); oldvar = var; } Sleep(20); Changing a variable, by itself, cannot get us out of a wait. We sleep 20 ms. each time through the loop. This is polling, but the sleep keeps it from being wasteful. Leaving sleep out makes it wasteful. Copyright © 1997 – 2016 Curt Hill
30
WaitForObject There are two that are used
Single and multiple Signatures: DWORD WINAPI WaitForSingleObject( _In_ HANDLE hHandle, _In_ DWORD dwMilliseconds ); DWORD WINAPIWaitForMultipleObjectsEx( _In_ DWORD nCount, _In_ const HANDLE *lpHandles, _In_ BOOL bWaitAll, _In_ DWORD dwMilliseconds, _In_ BOOL bAlertable ); Copyright © 1997 – 2016 Curt Hill
31
WaitForSingleObject The thread is suspended until this function returns This is not a busy wait Two parameters An object handle – consider soon Timeout value in milliseconds Returns a DWORD which says how the wait was terminated See next screen Copyright © 1997 – 2016 Curt Hill
32
Wait Returns There are several possible returns: WAIT_OBJECT_0
The object signaled WAIT_TIMEOUT The timer fired without the object signaling WAIT_ABANDONED The thread owning the object terminated before the object signaled WAIT_FAILED No waiting occurred – use GetLastError for this one Copyright © 1997 – 2016 Curt Hill
33
WaitForMultipleObjects
Similar to single except we pass an array of objects And a count to say how many There is also a Boolean that indicates to wait for any one of these or all of them AND or OR them Its return also introduces other WAIT_OBJECTs and WAIT_ABANDONEDs WAIT_OBJECT_1, WAIT_OBJECT_2 … If the return is WAIT_OBJECT_0 + N then the Nth item signaled If the return is WAIT_ABANDONED + N then the Nth item’s thread terminated Copyright © 1997 – 2016 Curt Hill
34
Wait Objects What events may a WaitForObject function consider?
This is not an object in class sense A partial list includes: Event Mutex Process Semaphore Thread Do you think more explanation is needed? There are several others as well Copyright © 1997 – 2016 Curt Hill
35
Wait objects Again The wait objects do not have to be of the same type in WaitForMultipleObjects There could be a mix of different types When either a process or thread ends this constitutes an event Thus we may use the handle of either a process or thread in the wait Copyright © 1997 – 2016 Curt Hill
36
Summary on Wait Waits are best used when one of the synchronization APIs cannot be used Exception is mutex, which requires the waits Generally it is better to use a synchronization API Copyright © 1997 – 2016 Curt Hill
37
Event An event is a control structure with one of two states
Signaled or not signaled We may then do a wait on an event until it is signaled The functions involved are CreateEvent SignalEvent ResetEvent Copyright © 1997 – Curt Hill
38
Create Event The CreateEvent returns a handle
It takes four parameters: LPSECURITY_ATTRIBUTES – may be NULL BOOL – TRUE requires manual reset BOOL – TRUE means it starts signaled LPCTSTR – Name, which may be NULL The returned event may be used in a Wait Handles other than Events may be waited for as well Copyright © 1997 – Curt Hill
39
Manual and Automatic The second parameter is whether the event needs a Reset A TRUE means that the user has to manually do the Reset when a thread is released from a Wait A FALSE means that only one thread is released from a Wait and then it is reset Copyright © 1997 – Curt Hill
40
Setting Events SetEvent(handle) makes the event to be in the signaled state A ResetEvent(handle) makes the event to be not signaled This is not usually needed with an automatic event Copyright © 1997 – Curt Hill
41
Mutexs A Mutex is similar to a critical section
Somewhat different usage Unlike a critical section it may be used by multiple processes Much less needed but very valuable when it is The steps are to: Create or Open Release Close the handle Copyright © 1997 – 2016 Curt Hill
42
Signatures HANDLE WINAPI CreateMutex( _In_opt_ LPSECURITY_ATTRIBUTES lpMutexAttributes, _In_ BOOL bInitialOwner, _In_opt_ LPCTSTR lpName ); HANDLE WINAPI OpenMutex( _In_ DWORD dwDesiredAccess, _In_ BOOL bInheritHandle, _In_ LPCTSTR lpName ); BOOL WINAPI ReleaseMutex( _In_ HANDLE hMutex ); Copyright © 1997 – 2016 Curt Hill
43
Ownership A mutex may be owned by only one thread on the system at a time The owner is not the creator Mutex may be created as owned or not owned The ReleaseMutex releases ownership OpenMutex gets a handle for a named mutex that some other process created Copyright © 1997 – 2016 Curt Hill
44
Usage One process does the CreateMutex
It retains the handle If the owner parameter is false then it is not owned by the thread A thread obtains the ownership for the mutex by using a Wait for Single or Multiple Object It will wait until the mutex is not owned Then it will own the mutex until it releases it Copyright © 1997 – 2016 Curt Hill
45
Conclusion Multiple threads and synchronization are tricky
This presentation may or may not have given you enough information to do There is one more and then some demonstration programs Spawning threads Copyright © 1997 – Curt Hill
Similar presentations
© 2025 SlidePlayer.com. Inc.
All rights reserved.