Win32API クリティカルセクションによるスレッドの排他制御

クリティカルセクションによるスレッドの同期制御

使用するAPI

  • InitializeCriticalSection

  • EnterCriticalSection

  • LeaveCriticalSection

  • DeleteCriticalSection

  • _beginthreadex

  • WaitForMultipleObjects

  • CloseHandle



  • CRITICAL_SECTION構造体は以下のように定義されていた(VisualStudio2005)

    ////////////////////////////////////////////////////////////
    //WinNt.h
    
    typedef struct _RTL_CRITICAL_SECTION {
        PRTL_CRITICAL_SECTION_DEBUG DebugInfo;
    
        //
        //  The following three fields control entering and exiting the critical
        //  section for the resource
        //
    
        LONG LockCount;
        LONG RecursionCount;
        HANDLE OwningThread;        // from the thread's ClientId->UniqueThread
        HANDLE LockSemaphore;
        ULONG_PTR SpinCount;        // force size on 64-bit systems when packed
    } RTL_CRITICAL_SECTION, *PRTL_CRITICAL_SECTION;
    
    /////////////////////////////////////////////////
    //WinBase.h
    
    typedef RTL_CRITICAL_SECTION CRITICAL_SECTION;
    typedef PRTL_CRITICAL_SECTION PCRITICAL_SECTION;
    typedef PRTL_CRITICAL_SECTION LPCRITICAL_SECTION;



    サンプルプログラムは、10スレッド起動し、それそれのスレッドがint型変数g_nCountをインクリメントする際に排他制御を行う。この排他制御により、g_nCountが正常に1ずつインクリメントされる。EnterCriticalSectionとLeaveCriticalSectionをコメントアウトすると、排他制御の効果がなくなることが分かる。

    #include <windows.h>
    #include <process.h>
    
    int g_nCount;
    CRITICAL_SECTION cs;
    
    unsigned int WINAPI ThreadFunc(LPVOID arg)
    {
    	int i;
    	for (i = 0; i < 100; i++) {
    		EnterCriticalSection(&cs);
    		printf("%d\n", g_nCount++);
    		LeaveCriticalSection(&cs);
    		Sleep(50);
    	}
    	return 0;
    }
    
    
    int main()
    {
    	HANDLE hThreads[10];
    	int nNumberOfThreads = sizeof(hThreads) / sizeof(hThreads[0]);
    	unsigned int uiThreadId;
    	int i;
    	DWORD dwRet;
    
    	InitializeCriticalSection(&cs);
    
    	for (i = 0; i < nNumberOfThreads; i++) {
    	
    		hThreads[i] = (HANDLE)_beginthreadex(NULL,
    				0,
    				ThreadFunc,
    				NULL,
    				0,
    				&uiThreadId);
    
    		if (hThreads[i] == NULL) {
    			printf("_beginthreadex failed %d\n", i);
    		}
    
    	}
    
    	dwRet = WaitForMultipleObjects(
    		nNumberOfThreads, 
    		hThreads, 
    		TRUE, 
    		INFINITE);
    
    	if (dwRet != WAIT_OBJECT_0) {
    		puts("WaitForMultipleOnject Error");
    	}
    
    	for (i = 0; i < nNumberOfThreads; i++) {
    		CloseHandle(hThreads[i]);
    	}
    
    	DeleteCriticalSection(&cs);
    
    	return 0;
    }