Bagikan melalui


Menggunakan Objek Mutex

Anda dapat menggunakan objek mutex untuk melindungi sumber daya bersama dari akses bersamaan oleh beberapa utas atau proses. Setiap utas harus menunggu untuk menguasai mutex sebelum dapat mengeksekusi kode yang mengakses sumber daya bersama. Misalnya, jika beberapa utas berbagi akses ke database, utas dapat menggunakan objek mutex untuk mengizinkan hanya satu utas pada satu waktu untuk menulis ke database.

Contoh berikut menggunakan fungsiCreateMutex untuk membuat objek mutex dan fungsiCreateThread untuk membuat utas pekerja.

Ketika utas proses ini menulis ke database, pertama-tama meminta kepemilikan mutex menggunakan fungsi WaitForSingleObject. Jika utas mendapatkan kepemilikan mutex, ia menulis ke basis data dan kemudian melepaskan kepemilikannya atas mutex menggunakan fungsi ReleaseMutex.

Contoh ini menggunakan penanganan pengecualian terstruktur untuk memastikan bahwa utas melepaskan objek mutex dengan benar. Blok kode __finally dijalankan tidak peduli bagaimana blok __try berakhir (kecuali blok __try menyertakan panggilan ke fungsiTerminateThread). Ini mencegah objek mutex ditinggalkan secara tidak sengaja.

Jika mutex ditinggalkan, utas yang memiliki mutex tidak melepaskannya dengan benar sebelum mengakhirinya. Dalam hal ini, status sumber daya bersama tidak dapat ditentukan, dan menggunakan mutex secara terus menerus dapat mengaburkan kesalahan yang berpotensi serius. Beberapa aplikasi mungkin mencoba memulihkan sumber daya ke status yang konsisten; contoh ini hanya mengembalikan kesalahan dan berhenti menggunakan mutex. Untuk informasi selengkapnya, lihat Objek 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; 
}