使用 Mutex 物件
您可以使用 mutex 物件 來保護共用資源,避免多個線程或進程同時存取。 每個線程都必須等候 Mutex 的擁有權,才能執行存取共用資源的程式代碼。 例如,如果數個線程共享資料庫的存取權,線程就可以使用 mutex 物件一次只允許一個線程寫入資料庫。
下列範例會使用 CreateMutex 函式來建立 mutex 物件,以及使用 CreateThread 函式來建立工作執行緒。
當這個進程的線程寫入資料庫時,它會先使用 waitForSingleObject 函式來要求 mutex 的擁有權。 如果線程取得 mutex 的擁有權,它會寫入資料庫,然後使用 ReleaseMutex 函式釋放其 mutex 的擁有權。
此範例會使用結構化例外狀況處理來確保線程正確地釋放 mutex 物件。 不論 __try 區塊如何終止,都會執行程式代碼 __finally 區塊(除非 __try 區塊包含對 TerminateThread 函式的呼叫)。 這可防止 Mutex 物件不小心被遺棄。
如果某個 Mutex 被放棄,則持有該 Mutex 的執行緒在終止前沒有正確釋放它。 在此情況下,共用資源的狀態不確定,而且繼續使用 Mutex 可能會遮蔽潛在的嚴重錯誤。 某些應用程式可能會嘗試將資源還原為一致的狀態,但此範例僅會返回錯誤並停止使用 mutex。 如需詳細資訊,請參閱 Mutex Objects。
#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;
}