9

我正在研究使用互斥锁保护全局双精度的示例,但是出现错误-

Lab7.exe 中 0x77b6308e 处的未处理异常: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

4 回答 4

13

代码中剩余的错误在于对WaitForMultipleObjects(). 您将第三个参数设置为0( FALSE) 以便主线程在 10 个线程中的任何一个完成后立即解除阻塞。

这会导致调用DeleteCriticalSection()在所有线程完成之前执行,当(可能)9 个其他线程之一启动并调用EnterCriticalSection().

于 2011-05-12T15:05:58.987 回答
4

您正在编写超出threads[10]数组末尾的内容:

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

threads只有10号!

于 2011-05-12T14:51:08.767 回答
4

您的问题是 WaitForMultipleObjects 没有等待所有线程完成,导致关键部分被过早删除。根据MSDN,第三个参数是

bWaitAll [输入]

如果此参数为 TRUE,则函数在 >lpHandles 数组中的所有对象的状态都发出信号时返回。如果为 FALSE,则当任何一个对象的状态设置为已发出信号时,该函数将返回。在后一种情况下,返回值表示对象>其状态导致函数返回。

您将其设置为 0,它会在您的任何一个线程完成时返回。这会导致以下 DeleteCriticalSection 在仍有线程等待访问它时运行。

于 2011-05-12T14:52:04.443 回答
2

您还应该将 score 声明为 volatile,这样就不会出现缓存值问题。

于 2011-06-22T21:17:48.760 回答