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);

}

アップデート:

ループが 10 ではなく 1000 に設定されている問題を修正した後もエラーが発生しましたが、ミューテックスを参照するコードをコメントアウトしたところ、エラーは発生しませんでした。

CRITICAL_SECTION score_mutex; 
EnterCriticalSection(&score_mutex); 
LeaveCriticalSection(&score_mutex); 
InitializeCriticalSection(&score_mutex); 
DeleteCriticalSection(&score_mutex); 

更新 2

慣習に従って、スレッドは 0 を返します (長い 1 週間でした!)

私はミューテックス関連のコードを追加しようとしましたが、CRITICAL_SECTION、InitializeCriticalSection、およびDeleteCriticalSectionがすべて追加された状態で、プログラムはコンパイルされて正常に実行されます(もちろんダブルの競合状態の問題を除く)。問題はEnterCriticalSectionにあるようですまたは LeaveCriticalSection を追加するとエラーが再発するためです。

4

4 に答える 4

13

コードの残りのバグは、 への呼び出しにありWaitForMultipleObjects()ます。10 個のスレッドのいずれかが終了するとすぐにメイン スレッドのブロックが解除されるように、3 番目のパラメーターを0( ) に設定します。FALSE

これにより、DeleteCriticalSection()すべてのスレッドが終了する前に呼び出しが実行され、(おそらく) 9 つの他のスレッドの 1 つが開始して を呼び出すと、アクセス違反が発生します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によると、3 番目の引数は

bWaitAll [入力]

このパラメーターが TRUE の場合、>lpHandles 配列内のすべてのオブジェクトの状態が通知されると、関数は戻ります。FALSE の場合、オブジェクトのいずれかの状態がシグナル状態に設定されている場合、関数は戻ります。後者の場合、戻り値はオブジェクトを示し、その状態によって関数が戻ります。

これを 0 に設定すると、いずれかのスレッドが完了すると返されます。これにより、アクセスを待機しているスレッドが残っている間に、次の DeleteCriticalSection が実行されます。

于 2011-05-12T14:52:04.443 に答える
2

また、キャッシュされた値の問題が発生しないように、スコアを揮発性として宣言する必要があります。

于 2011-06-22T21:17:48.760 に答える