Download presentation
Presentation is loading. Please wait.
Published byHilary Brooks Modified over 9 years ago
1
Win32 Programming Lesson 11: User-mode Thread Sync (aka: How to crash your machine without really trying…)
2
Where are we? We’ve got thread basics worked out… even priorities But right now, all the examples are sort-of contrived… Need to understand how to communicate from thread to thread
3
Thread Problems When we share data between threads, bad things can happen Look at the following example code… What’s wrong? Can replace using “interlocked” functions
4
InterlockedExchangeAdd LONG InterlockedExchangeAdd ( PLONG plAddend, LONG lIncrement ); What could be simpler – promises Atomic access to *plAddend
5
Family LONG InterlockedExchange( PLONG plTarget, LONG lValue ); PVOID InterlockedExchangePointer( PVOID* ppvTarget, PVOID pvValue );
6
Spinlock… // Global variable indicating whether a shared re source is in use or not BOOL g_fResourceInUse = FALSE; void Func1() { // Wait to access the resource. while (InterlockedExchange ( &g_fResourceInUse, TRUE) == TRUE) Sleep(0); // Access the resource. // We no longer need to access the resource. InterlockedExchange(&g_fResourceInUse, FALSE); }
7
Spinlocks (cntd) Be careful on a single processor machine Is Sleep(0) the best call? Why?
8
More Interlocked Calls… PVOID InterlockedCompareExchange( PLONG plDestination, LONG lExchange, LONG lComparand ); PVOID InterlockedCompareExchangePointer( PVOID* ppvDestination, PVOID pvExchange, PVOID pvComparand ); Basically, update on equality…
9
Cashing in… (groan) When a CPU accesses memory, it does not read a single byte, but instead fills a “cache line” (32 or 64 bytes, aligned on a 32 or 64 byte boundary) If the cache becomes dirty it is flushed Has a huge impact on how to design data structures for speed
10
_declspec(align32) See MSDNMSDN Basically, forces alignment on a cache boundary See: declspec example…
11
DON’T DO THIS! volatile BOOL g_fFinishedCalculation = FALSE; int WINAPI WinMain(...) { CreateThread(..., RecalcFunc,...); // Wait for the recalculation to complete. while (!g_fFinishedCalculation) ; } DWORD WINAPI RecalcFunc(PVOID pvParam) { // Perform the recalculation. g_fFinishedCalculation = TRUE; return(0); }
12
Volatile? Well? Well? Oops (optimizer…): ; Copy the value into a register Label: MOV Reg0, [g_fFinishedCalculation] TEST Reg0, 0; Is the value 0? JMP Reg0 == 0, Label; The register is 0, try again... ; The register is not 0 (end of loop)
13
Critical Section Can mark a code section as critical This prevents any other thread accessing the resources within the critical section Other threads do still get scheduled though…
14
Look at this… const int MAX_TIMES = 1000; int g_nIndex = 0; DWORD g_dwTimes[MAX_TIMES]; DWORD WINAPI FirstThread(PVOID pvParam) { while (g_nIndex < MAX_TIMES) { g_dwTimes[g_nIndex] = GetTickCount(); g_nIndex++; } return(0); } DWORD WINAPI SecondThread(PVOID pvParam) { while (g_nIndex < MAX_TIMES) { g_nIndex++; g_dwTimes[g_nIndex - 1] = GetTickCount(); } return(0); }
15
Fixed.. const int MAX_TIMES = 1000; int g_nIndex = 0; DWORD g_dwTimes[MAX_TIMES]; CRITICAL_SECTION g_cs; DWORD WINAPI FirstThread(PVOID pvParam) { while (g_nIndex < MAX_TIMES) { EnterCriticalSection(&g_cs); g_dwTimes[g_nIndex] = GetTickCount(); g_nIndex++; LeaveCriticalSection(&g_cs); } return(0); } DWORD WINAPI SecondThread(PVOID pvParam) { while (g_nIndex < MAX_TIMES) { EnterCriticalSection(&g_cs); g_nIndex++; g_dwTimes[g_nIndex - 1] = GetTickCount(); LeaveCriticalSection(&g_cs); } return(0); }
16
But… You MUST remember to leave a critical section else no other thread can use the resource And the Devil really is in the details
17
Initialization Before you can use a CRITICAL SECTION you must initialize it VOID InitializeCriticalSection(PCRITICAL_SE CTION pcs); Results undefined if you don’t do this… BTW, what do you notice about the return?
18
Entering… If no thread is using the resource, continue Else put the calling thread into a WAIT state VOID EnterCriticalSection(PCRITICAL_SE CTION pcs); Can use: BOOL TryEnterCriticalSection(PCRITICAL_SE CTION pcs); Don’t wait: return TRUE/FALSE
19
Leaving VOID LeaveCriticalSection(PCRITICAL_SE CTION pcs); If we’re done with this Section check for any other threads waiting and mark 1 as schedulable VOID DeleteCriticalSection(PCRITICAL_SE CTION pcs);
20
Tips Use ONE critical section per shared resource Access multiple resources using multiple critical sections Don’t hold on to a critical section for a long time
21
Next… Thread Synchronization with Kernel objects
Similar presentations
© 2025 SlidePlayer.com. Inc.
All rights reserved.