Share via


使用 Mutex 物件

您可以使用 mutex 物件 來保護共用資源,避免多個執行緒或進程同時存取。 每個執行緒都必須等候 mutex 的擁有權,才能執行可存取共用資源的程式碼。 例如,如果數個執行緒共用資料庫的存取權,執行緒可以使用 mutex 物件一次只允許一個執行緒寫入資料庫。

下列範例會使用 CreateMutex 函式來建立 mutex 物件和 CreateThread 函式來建立背景工作執行緒。

當這個進程的執行緒寫入資料庫時,它會先使用 WaitForSingleObject 函式要求 Mutex 的擁有權。 如果執行緒取得 mutex 的擁有權,它會寫入資料庫,然後使用 ReleaseMutex 函式釋放 mutex 的擁有權。

這個範例會使用結構化例外狀況處理來確保執行緒正確地釋放 mutex 物件。 不論__try區塊如何終止 (,除非__try區塊包含TerminateThread函式) 的呼叫,否則會執行程式碼__finally區塊。 這可防止不小心放棄 mutex 物件。

如果已放棄 Mutex,擁有 mutex 的執行緒在終止之前並未正確釋放。 在此情況下,共用資源的狀態不確定,而且繼續使用 Mutex 可能會遮蔽潛在的嚴重錯誤。 某些應用程式可能會嘗試將資源還原為一致狀態;此範例只會傳回錯誤,並使用 mutex 停止。 如需詳細資訊,請參閱 Mutex 物件

#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; 
}