Exceção não tratada/local de gravação de violação de acesso em um exemplo de Mutex
-
12-11-2019 - |
Pergunta
Estou trabalhando em um exemplo de proteção de um duplo global usando mutexes, mas recebo o erro -
Exceção não atendida em 0x77b6308e em lab7.exe:0xC0000005:Acesso Local de Redação de Violação 0x00000068.
Presumo que isso esteja relacionado ao acesso à pontuação.(O duplo global)
#include <windows.h>
#include <iostream>
#include <process.h>
double score = 0.0;
HANDLE threads[10];
CRITICAL_SECTION score_mutex;
unsigned int __stdcall MyThread(void *data)
{
EnterCriticalSection(&score_mutex);
score = score + 1.0;
LeaveCriticalSection(&score_mutex);
return 0;
}
int main()
{
InitializeCriticalSection(&score_mutex);
for (int loop = 0; loop < 10; loop++)
{
threads[loop] = (HANDLE) _beginthreadex(NULL, 0, MyThread, NULL, 0, NULL);
}
WaitForMultipleObjects(10, threads, 0, INFINITE);
DeleteCriticalSection(&score_mutex);
std::cout << score;
while(true);
}
Atualizar:
Depois de corrigir o problema com o loop sendo definido como 1000 em vez de 10, o erro ainda ocorreu, porém quando comentei os trechos de código referentes ao mutex o erro não ocorreu.
CRITICAL_SECTION score_mutex;
EnterCriticalSection(&score_mutex);
LeaveCriticalSection(&score_mutex);
InitializeCriticalSection(&score_mutex);
DeleteCriticalSection(&score_mutex);
Atualização 2
Os tópicos retornam 0 conforme a convenção (foi uma semana longa!)
Tentei adicionar novamente o código relacionado ao mutex, e o programa irá compilar e funcionar bem (exceto os problemas de condição de corrida com o dobro, é claro) com CRITICAL_SECTION, InitializeCriticalSection e DeleteCriticalSection, todos adicionados novamente.O problema parece ser com EnterCriticalSection ou LeaveCriticalSection, pois o erro ocorre novamente quando eu os adiciono.
Solução
O bug restante no seu código está na chamada para WaitForMultipleObjects()
.Você define o terceiro parâmetro como 0
(FALSE
) de modo que o thread principal seja desbloqueado assim que qualquer dos 10 fios termina.
Isso faz com que a chamada seja DeleteCriticalSection()
para ser executado antes que todos os threads sejam concluídos, criando uma violação de acesso quando um dos (possivelmente) 9 outros threads inicia e chama EnterCriticalSection()
.
Outras dicas
Você está escrevendo além do final do seu threads[10]
variedade:
for (int loop = 0; loop < 1000; loop++){
threads[loop];
}
threads
só tem tamanho 10!
Seu problema é que WaitForMultipleObjects não está aguardando a conclusão de todos os threads, fazendo com que a seção crítica seja excluída prematuramente.De acordo com MSDN, o terceiro argumento é
bEspere tudo [in]
Se este parâmetro for TRUE, a função retorna quando o estado de todos os objetos do array >lpHandles for sinalizado.Se for FALSO, a função retornará quando o estado de qualquer um dos objetos for definido como sinalizado.Neste último caso, o valor de retorno indica o objeto cujo estado causou o retorno da função.
Você define isso como 0, que retorna quando QUALQUER UM dos seus threads é concluído.Isso faz com que o seguinte DeleteCriticalSection seja executado enquanto ainda há threads aguardando para acessá-lo.
Você também deve declarar a pontuação como volátil para não ter problemas de valor em cache.