뮤텍스 개체 사용

뮤텍스 개체를 사용하여 여러 스레드 또는 프로세스의 동시 액세스로부터 공유 리소스를 보호할 수 있습니다. 각 스레드는 공유 리소스에 액세스하는 코드를 실행하기 전에 뮤텍스의 소유권을 기다려야 합니다. 예를 들어 여러 스레드가 데이터베이스에 대한 액세스를 공유하는 경우 스레드는 뮤텍스 개체를 사용하여 한 번에 하나의 스레드만 데이터베이스에 쓸 수 있도록 허용할 수 있습니다.

다음 예제에서는 CreateMutex 함수를 사용하여 뮤텍스 개체를 만들고 CreateThread 함수를 사용하여 작업자 스레드를 만듭니다.

이 프로세스의 스레드가 데이터베이스에 쓰면 먼저 WaitForSingleObject 함수를 사용하여 뮤텍스의 소유권을 요청합니다. 스레드가 뮤텍스의 소유권을 가져오는 경우 데이터베이스에 쓴 다음 ReleaseMutex 함수를 사용하여 뮤텍스의 소유권을 해제합니다.

이 예제에서는 구조적 예외 처리를 사용하여 스레드가 뮤텍스 개체를 제대로 해제하도록 합니다. 코드의 __finally 블록은 __try 블록이 종료되는 방식에 관계없이 실행됩니다(__try 블록에 TerminateThread 함수에 대한 호출이 포함되어 있지 않은 경우). 이렇게 하면 뮤텍스 개체가 실수로 중단되지 않습니다.

뮤텍스가 중단된 경우 뮤텍스를 소유한 스레드가 종료하기 전에 제대로 해제되지 않았습니다. 이 경우 공유 리소스의 상태는 확정되지 않으며 뮤텍스를 계속 사용하면 잠재적으로 심각한 오류가 발생할 수 있습니다. 일부 애플리케이션은 리소스를 일관된 상태로 복원하려고 시도할 수 있습니다. 이 예제에서는 단순히 오류를 반환하고 뮤텍스 사용을 중지합니다. 자세한 내용은 뮤텍스 개체를 참조하세요.

#include <windows.h>
#include <stdio.h>

#define THREADCOUNT 2

HANDLE ghMutex; 

DWORD WINAPI WriteToDatabase( LPVOID );

int main( void )
{
    HANDLE aThread[THREADCOUNT];
    DWORD ThreadID;
    int i;

    // Create a mutex with no initial owner

    ghMutex = CreateMutex( 
        NULL,              // default security attributes
        FALSE,             // initially not owned
        NULL);             // unnamed mutex

    if (ghMutex == NULL) 
    {
        printf("CreateMutex error: %d\n", GetLastError());
        return 1;
    }

    // Create worker threads

    for( i=0; i < THREADCOUNT; i++ )
    {
        aThread[i] = CreateThread( 
                     NULL,       // default security attributes
                     0,          // default stack size
                     (LPTHREAD_START_ROUTINE) WriteToDatabase, 
                     NULL,       // no thread function arguments
                     0,          // default creation flags
                     &ThreadID); // receive thread identifier

        if( aThread[i] == NULL )
        {
            printf("CreateThread error: %d\n", GetLastError());
            return 1;
        }
    }

    // Wait for all threads to terminate

    WaitForMultipleObjects(THREADCOUNT, aThread, TRUE, INFINITE);

    // Close thread and mutex handles

    for( i=0; i < THREADCOUNT; i++ )
        CloseHandle(aThread[i]);

    CloseHandle(ghMutex);

    return 0;
}

DWORD WINAPI WriteToDatabase( LPVOID lpParam )
{ 
    // lpParam not used in this example
    UNREFERENCED_PARAMETER(lpParam);

    DWORD dwCount=0, dwWaitResult; 

    // Request ownership of mutex.

    while( dwCount < 20 )
    { 
        dwWaitResult = WaitForSingleObject( 
            ghMutex,    // handle to mutex
            INFINITE);  // no time-out interval
 
        switch (dwWaitResult) 
        {
            // The thread got ownership of the mutex
            case WAIT_OBJECT_0: 
                __try { 
                    // TODO: Write to the database
                    printf("Thread %d writing to database...\n", 
                            GetCurrentThreadId());
                    dwCount++;
                } 

                __finally { 
                    // Release ownership of the mutex object
                    if (! ReleaseMutex(ghMutex)) 
                    { 
                        // Handle error.
                    } 
                } 
                break; 

            // The thread got ownership of an abandoned mutex
            // The database is in an indeterminate state
            case WAIT_ABANDONED: 
                return FALSE; 
        }
    }
    return TRUE; 
}