Необработанное исключение / место записи нарушения прав доступа в примере Mutex - PullRequest
9 голосов
/ 12 мая 2011

Я работаю над примером защиты глобального двойника с помощью мьютексов, однако я получаю сообщение об ошибке -

Необработанное исключение в 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 ]

13 голосов
/ 12 мая 2011

Оставшаяся ошибка в вашем коде заключается в вызове WaitForMultipleObjects(). Для третьего параметра установлено значение 0 (FALSE), чтобы основной поток разблокировался, как только любой из 10 потоков завершится.

Это приводит к выполнению вызова DeleteCriticalSection() до завершения всех потоков, создавая нарушение прав доступа, когда один из (возможно) 9 других потоков запускается и вызывает EnterCriticalSection().

4 голосов
/ 12 мая 2011

Ваша проблема в том, что WaitForMultipleObjects не ожидает завершения всех потоков, что приводит к преждевременному удалению критического раздела.Согласно MSDN , третий аргумент -

bWaitAll [in]

Если этот параметр равен TRUE, функция возвращается, когда состояние всех объектов в> Массив lpHandles сигнализируется.Если FALSE, функция возвращается, когда состояние любого из> объектов установлено как сигнальное.В последнем случае возвращаемое значение указывает объект>, состояние которого вызвало возврат функции.

Вы устанавливаете это значение в 0, которое возвращается, когда ЛЮБОЙ из ваших потоков завершается.Это приводит к выполнению следующей команды DeleteCriticalSection, пока есть потоки, ожидающие доступа к ней.

4 голосов
/ 12 мая 2011

Вы пишете за пределами вашего массива threads[10]:

for (int loop = 0; loop < 1000; loop++){
     threads[loop];
}

threads имеет только размер 10!

2 голосов
/ 23 июня 2011

Вы также должны объявить счет как энергозависимый, чтобы у вас не было проблемы с кэшированным значением.

...