Uso di oggetti Mutex

È possibile usare un oggetto mutex per proteggere una risorsa condivisa dall'accesso simultaneo da più thread o processi. Ogni thread deve attendere la proprietà del mutex prima di poter eseguire il codice che accede alla risorsa condivisa. Ad esempio, se diversi thread condividono l'accesso a un database, i thread possono usare un oggetto mutex per consentire a un solo thread alla volta di scrivere nel database.

Nell'esempio seguente viene usata la funzione CreateMutex per creare un oggetto mutex e la funzione CreateThread per creare thread di lavoro.

Quando un thread di questo processo scrive nel database, richiede innanzitutto la proprietà del mutex usando la funzione WaitForSingleObject . Se il thread ottiene la proprietà del mutex, scrive nel database e rilascia la proprietà del mutex usando la funzione ReleaseMutex .

In questo esempio viene usata la gestione delle eccezioni strutturate per garantire che il thread rilasci correttamente l'oggetto mutex. Il blocco __finally di codice viene eseguito indipendentemente dal modo in cui termina il blocco di __try (a meno che il blocco di __try includa una chiamata alla funzione TerminateThread ). Ciò impedisce all'oggetto mutex di essere abbandonato inavvertitamente.

Se un mutex viene abbandonato, il thread di proprietà del mutex non lo ha rilasciato correttamente prima di terminare. In questo caso, lo stato della risorsa condivisa è indeterminato e continua a usare il mutex può nascondere un errore potenzialmente grave. Alcune applicazioni potrebbero tentare di ripristinare la risorsa in uno stato coerente; questo esempio restituisce semplicemente un errore e si arresta usando il mutex. Per altre informazioni, vedere Oggetti 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; 
}