Presentation is loading. Please wait.

Presentation is loading. Please wait.

Win32 Programming Lesson 11: User-mode Thread Sync (aka: How to crash your machine without really trying…)

Similar presentations


Presentation on theme: "Win32 Programming Lesson 11: User-mode Thread Sync (aka: How to crash your machine without really trying…)"— Presentation transcript:

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


Download ppt "Win32 Programming Lesson 11: User-mode Thread Sync (aka: How to crash your machine without really trying…)"

Similar presentations


Ads by Google