Verwenden von Mutex-Objekten
Sie können ein Mutex-Objekt verwenden, um eine freigegebene Ressource vor dem gleichzeitigen Zugriff durch mehrere Threads oder Prozesse zu schützen. Jeder Thread muss auf den Besitz des Mutex warten, bevor er den Code ausführen kann, der auf die freigegebene Ressource zugreift. Wenn beispielsweise mehrere Threads den Zugriff auf eine Datenbank gemeinsam nutzen, können die Threads ein Mutex-Objekt verwenden, damit jeweils nur ein Thread in die Datenbank schreiben kann.
Im folgenden Beispiel wird die CreateMutex-Funktion zum Erstellen eines Mutex-Objekts und die CreateThread-Funktion zum Erstellen von Arbeitsthreads verwendet.
Wenn ein Thread dieses Prozesses in die Datenbank schreibt, wird zuerst der Besitz des Mutex mithilfe der WaitForSingleObject-Funktion angefordert . Wenn der Thread den Besitz des Mutex erhält, schreibt er in die Datenbank und gibt dann seinen Besitz des Mutex mithilfe der ReleaseMutex-Funktion frei.
In diesem Beispiel wird die strukturierte Ausnahmebehandlung verwendet, um sicherzustellen, dass der Thread das Mutex-Objekt ordnungsgemäß freigibt. Der __finally Codeblock wird unabhängig davon ausgeführt, wie der __try Block beendet wird (es sei denn, der __try Block enthält einen Aufruf der TerminateThread-Funktion ). Dadurch wird verhindert, dass das Mutex-Objekt versehentlich verlassen wird.
Wenn ein Mutex abgebrochen wird, hat der Thread, der den Mutex besitzt, ihn vor dem Beenden nicht ordnungsgemäß freigegeben. In diesem Fall ist der Status der freigegebenen Ressource unbestimmt, und die fortgesetzte Verwendung des Mutex kann einen potenziell schwerwiegenden Fehler verschleiern. Einige Anwendungen versuchen möglicherweise, die Ressource in einen konsistenten Zustand wiederherzustellen. In diesem Beispiel wird einfach ein Fehler zurückgegeben und die Verwendung des Mutex beendet. Weitere Informationen finden Sie unter Mutex-Objekte.
#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;
}