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