Remarque
L’accès à cette page nécessite une autorisation. Vous pouvez essayer de vous connecter ou de modifier des répertoires.
L’accès à cette page nécessite une autorisation. Vous pouvez essayer de modifier des répertoires.
Vous pouvez utiliser un objet mutex pour protéger une ressource partagée contre l’accès simultané par plusieurs threads ou processus. Chaque thread doit attendre la propriété du mutex avant de pouvoir exécuter le code qui accède à la ressource partagée. Par exemple, si plusieurs threads partagent l’accès à une base de données, les threads peuvent utiliser un objet mutex pour autoriser un seul thread à la fois à écrire dans la base de données.
L’exemple suivant utilise la fonction CreateMutex pour créer un objet mutex et la fonction CreateThread pour créer des threads de travail.
Lorsqu’un thread de ce processus écrit dans la base de données, il demande d’abord la propriété du mutex à l’aide de la fonction WaitForSingleObject . Si le thread obtient la propriété du mutex, il écrit dans la base de données, puis libère sa propriété du mutex à l’aide de la fonction ReleaseMutex .
Avertissement
Risque d’interblocage avec délai d’expiration INFINITE : L’exemple ci-dessous utilise INFINITE comme paramètre de délai d’attente pour WaitForSingleObject. Dans le code de production, cela signifie que le thread appelant reste bloqué indéfiniment si le thread propriétaire est victime d’un interblocage, se bloque ou ne parvient pas à libérer le mutex. Envisagez d’utiliser une valeur de délai d’attente finie et d’implémenter une logique de nouvelle tentative avec la journalisation des diagnostics pour détecter les blocages potentiels. Utilisez des outils tels que l’extension du débogueur !handle (par exemple) !handle <handle> fou Wait Chain Traversal (GetThreadWaitChain) pour diagnostiquer les interblocages mutex.
Cet exemple utilise la gestion structurée des exceptions pour s’assurer que le thread libère correctement l’objet mutex. Le bloc __finally de code est exécuté indépendamment de la façon dont le bloc __try se termine (sauf si le bloc __try inclut un appel à la fonction TerminateThread ). Cela empêche l’abandon par inadvertance de l’objet mutex.
Si un mutex est abandonné, le thread qui possédait le mutex ne l’a pas correctement libéré avant de terminer. Dans ce cas, l’état de la ressource partagée est indéterminé et la poursuite de l’utilisation du mutex peut masquer une erreur potentiellement grave. Certaines applications peuvent tenter de restaurer la ressource à un état cohérent ; cet exemple retourne simplement une erreur et cesse d’utiliser le mutex. Pour plus d’informations, consultez 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;
}