メインプログラムを終了する前にスレッドを停止したい。このコードは正しいですか?(簡略化した例)
HANDLE hThread;
BOOL live = TRUE;
DWORD WINAPI Thread ( LPVOID lpParam )
{
..
while(live);
..
}
case WM_DESTROY:
{
live=FALSE;
WaitForSingleObject(hThread, INFINITE);
}
メインプログラムを終了する前にスレッドを停止したい。このコードは正しいですか?(簡略化した例)
HANDLE hThread;
BOOL live = TRUE;
DWORD WINAPI Thread ( LPVOID lpParam )
{
..
while(live);
..
}
case WM_DESTROY:
{
live=FALSE;
WaitForSingleObject(hThread, INFINITE);
}
スレッドを同期する最も安全な方法は、いくつかのカーネル オブジェクトを使用することです。あなたの場合、「終了」イベントを作成しCreateEvent
、スレッドコールバック関数内でそれを待つことができます:
#include <Windows.h>
#include <iostream>
using std::cout;
using std::cerr;
using std::endl;
DWORD WINAPI Callback(LPVOID lpVoid)
{
HANDLE hTerminateEvent = *(reinterpret_cast<HANDLE*>(lpVoid));
bool terminate = false;
while(!terminate)
{
DWORD retVal = WaitForSingleObject(hTerminateEvent, 0);
switch(retVal)
{
case WAIT_OBJECT_0:
cout << "Terminate Event signalled" << endl;
terminate = true;
break;
case WAIT_TIMEOUT:
cout << "Keep running..." << endl;
Sleep(1000);
break;
case WAIT_FAILED:
cerr << "WaitForSingleObject() failed" << endl;
terminate = true;
break;
}
}
return 0;
}
int main()
{
DWORD threadID = 0;
HANDLE hTerminateEvent = CreateEvent(0, FALSE, FALSE, 0);
HANDLE hThread = CreateThread(0, 0, Callback, &hTerminateEvent, 0, &threadID);
// allow some time to thread to live
Sleep(20000);
// set terminate event
if(!SetEvent(hTerminateEvent))
{
cerr << "SetEvent() failed" << endl;
return 1;
}
// wait for thread to terminate
DWORD retVal = WaitForSingleObject(hThread, INFINITE);
switch(retVal)
{
case WAIT_OBJECT_0:
cout << "Thread terminated" << endl;
break;
case WAIT_FAILED:
cerr << "WaitForSingleObject() failed" << endl;
break;
}
CloseHandle(hThread);
CloseHandle(hTerminateEvent);
return 0;
}
出力:
Keep running...
Keep running...
Keep running...
Keep running...
Keep running...
Keep running...
Keep running...
Keep running...
Keep running...
Keep running...
Keep running...
Keep running...
Keep running...
Keep running...
Keep running...
Keep running...
Keep running...
Keep running...
Keep running...
Keep running...
Terminate Event signalled
Thread terminated
スレッドが変更を認識できるようにするには、次のことlive
を行う必要がありますlive
volatile
。
volatile BOOL live = TRUE;
いいえ、正しくありません。スレッドが変更を確認できることを保証するものは何もありません。コンパイラは自由に最適化できます。
DWORD WINAPI Thread ( LPVOID lpParam )
{
..
while(live);
..
}
に:
DWORD WINAPI Thread ( LPVOID lpParam )
{
..
register bool temp=live;
while(temp);
..
}
それは明らかに機能しません。
経験則は次のとおりです。操作が安全であることを確認するための特定のメカニズムを使用しない限り、別のスレッドが変数を変更している間は、あるスレッドの変数にアクセスしないでください。そのルールに従えば、トラブルに巻き込まれません。