Critical Sections

< BACK  NEXT >
[oR]

A critical section identifies code that must be executed to completion before another piece of code can be executed. In the example presented in the previous section, the statements "g_fValue = g_fValue * g_fValue;" and "g_fValue = 3.0 + g_fValue;" should be marked as critical sections to ensure that both statements can be executed to completion before the other starts executing. If this is done, the only two possible results in g_fValue are 103 and 169. The spurious value of 130 will never occur.

To create and use a critical section you should:

  • Declare a CRITICAL_SECTION structure as a global variable, or a member variable of a class

  • Call the InitializeCriticalSection function to initialize this structure

  • Call EnterCriticalSection before the lines of code that form the critical sections

  • Call LeaveCriticalSection after the lines of code that form the critical sections

  • Call the DeleteCriticalSection function when the CRITICAL_SECTION is no longer required

All the critical section functions take a single argument that is a pointer to the CRITICAL_SECTION structure. You should treat this structure as a black box and not use the members contained in it. The code in Listing 6.1 declares a critical section structure g_cs, and creates two threads using thread functions f1 and f2. Each thread function performs an operation on a global float value "g_fValue". Because each thread is accessing a global function, the critical section structure g_cs is used to synchronize access to the global variable.

Listing 6.1 Using critical sections
 float g_fValue = 10.0; CRITICAL_SECTION g_cs; DWORD WINAPI f1(LPVOID); DWORD WINAPI f2(LPVOID); void Listing6_1() {   HANDLE hThread1, hThread2;   DWORD dwThreadID;   g_fValue = 10.0;   InitializeCriticalSection(&g_cs);   hThread1 = CreateThread(NULL, 0,       f1, NULL, 0, &dwThreadID);   hThread2 = CreateThread(NULL, 0,       f2, NULL, 0, &dwThreadID);   // Wait until thread 1 and thread 2 completes   WaitForSingleObject(hThread1, INFINITE);   WaitForSingleObject(hThread2, INFINITE);   DeleteCriticalSection(&g_cs);   CloseHandle(hThread1);   CloseHandle(hThread2);   cout   _T("Finished:")    g_fValue   endl; } DWORD WINAPI f1(LPVOID) {   EnterCriticalSection(&g_cs);   g_fValue = g_fValue * g_fValue;   LeaveCriticalSection(&g_cs);   return 0; } DWORD WINAPI f2(LPVOID) {   EnterCriticalSection(&g_cs);   g_fValue = (float)3.0 + g_fValue;   LeaveCriticalSection(&g_cs);   return 0; } 

In Listing 6.1 you will notice that WaitForSingleObject is called twice, once for each of the two threads. This causes the function Listing6_1 to block until both threads have terminated. This is important, since the call to DeleteCriticalSection cannot be made until both threads have finished using the critical section. WaitForMultipleObjects cannot be used for this purpose, since in Windows CE WaitForMultipleObjects only blocks until one of the threads terminates. This is described in more detail later.

Once one thread calls EnterCriticalSection, any other thread calling EnterCriticalSection using the same CRITICAL_SECTION structure will block until the first thread calls LeaveCriticalSection. When this happens, a thread blocked in EnterCriticalSection will unblock and can then execute the code in its critical section. Multiple threads can be blocked on calls to EnterCriticalSection, and you cannot predict which of these blocked threads will unblock. Note that creating a critical section does not ensure that the code in the critical section will execute to completion without interruption the normal thread-scheduling rules apply.

The following rules should be applied when using critical sections:

  • Always ensure that the LeaveCriticalSection call is made. For example, do not have "return" statements in the critical section code.

  • Do not introduce user interactions, such as a message box, in a critical section. Other threads will block until the user dismisses the message box.

  • Do not have code that takes a long time to execute in a critical section. You will end up blocking other threads, and they won't be able to execute their code.

You can declare multiple CRITICAL_SECTION structures to protect, for example, the access to different global variables. While this can improve the multithreading processing (since threads will not unnecessarily be blocked), it introduces the potential of deadlocks. For example, a thread could enter critical section 1 and then attempt to enter critical section 2. Another thread could enter critical section 2 and then attempt to enter critical section 1. If this happens simultaneously, a deadlock can occur. Using the rule described earlier, you can avoid this by always entering critical sections in the same order.


< BACK  NEXT >


Windows CE 3. 0 Application Programming
Windows CE 3.0: Application Programming (Prentice Hall Series on Microsoft Technologies)
ISBN: 0130255920
EAN: 2147483647
Year: 2002
Pages: 181

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net