Необработанное исключение / место записи нарушения прав доступа в примере Mutex
Я работаю над примером защиты глобального двойника с помощью мьютексов, однако я получаю ошибку -
Необработанное исключение в 0x77b6308e в Lab7.exe: 0xC0000005: Место записи нарушения прав доступа 0x00000068.
Я полагаю, это связано с доступом к счету? (Глобальный дубль)
#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);
}
Обновить:
После исправления проблемы с циклом, установленным в 1000 вместо 10, ошибка все еще произошла, однако, когда я закомментировал фрагменты кода, относящиеся к мьютексу, ошибка не произошла.
CRITICAL_SECTION score_mutex;
EnterCriticalSection(&score_mutex);
LeaveCriticalSection(&score_mutex);
InitializeCriticalSection(&score_mutex);
DeleteCriticalSection(&score_mutex);
Обновление 2
Потоки возвращают 0 согласно соглашению (это была длинная неделя!)
Я попытался добавить обратно в код, связанный с мьютексом, и программа скомпилируется и будет работать нормально (кроме проблем с условиями гонки с двойным курсом) с CRITICAL_SECTION, InitializeCriticalSection и DeleteCriticalSection все добавлены обратно. Проблема, как представляется, с EnterCriticalSection или LeaveCriticalSection, так как ошибка повторяется, когда я их добавляю.
4 ответа
Оставшаяся ошибка в вашем коде заключается в вызове WaitForMultipleObjects()
, Вы устанавливаете третий параметр на 0
(FALSE
) такой, что основной поток разблокируется, как только любой из 10 потоков завершается.
Это вызывает призыв к DeleteCriticalSection()
выполнить до завершения всех потоков, создавая нарушение прав доступа, когда один из (возможно) 9 других потоков запускается и вызывает EnterCriticalSection()
,
Ваша проблема в том, что WaitForMultipleObjects не ожидает завершения всех потоков, что приводит к преждевременному удалению критического раздела. Согласно MSDN, третий аргумент
bWaitAll [in]
Если этот параметр равен TRUE, функция возвращается, когда сигнализируется состояние всех объектов в массиве>lpHandles. Если FALSE, функция возвращается, когда состояние любого из> объектов установлено как сигнальное. В последнем случае возвращаемое значение указывает объект>, состояние которого вызвало возврат функции.
Вы устанавливаете это в 0, который возвращается, когда ЛЮБОЙ из ваших потоков завершается. Это приводит к тому, что следующая DeleteCriticalSection будет запущена, пока есть потоки, ожидающие доступа к ней.
Ты пишешь за конец своего threads[10]
массив:
for (int loop = 0; loop < 1000; loop++){
threads[loop];
}
threads
только имеет размер 10!
Вы также должны объявить счет как изменчивый, чтобы у вас не было проблемы с кэшированным значением.