遅刻の「言い訳」選手権

マルチスレッドプログラミングについていくつか教えて下さい。
マルチスレッドの基礎がまだ分かってないので初心者でも分かり易いようにお願いします。

1:イベントオブジェクトについて教えて下さい。
「イベントオブジェクト」の概念がよく分かりません。
○シグナル状態と非シグナル状態とはどういう状態なのでしょうか?
○自動リセットの場合ではどのタイミングで切り替わっているのでしょうか?(下記のソースの場合)
○手動リセットの場合ではどのタイミングで切り替えればよいのでしょうか?(下記のソースの場合)

2:CloseHandle() と ExitThread() について教えて下さい。
○この2つの関数の役割の違いについて教えて下さい。
「スレッドハンドルを閉じる=スレッドを終了」ではないのでしょうか?
また、これらの関数実行時にシグナル状態は気にする必要はありますか?(シグナル状態にしなくてよいのか?)


下記のソースは簡略化のためかなり省略されています。
DWORD WINAPI ThreadProc( DWORD i )
{
while( true )
{
DWORD r = WaitForMultipleObjects( 2, hEvent, FALSE, INFINITE );
if( r == WAIT_OBJECT_0 )
{
// 処理1
}
else if( r == WAIT_OBJECT_0 )
{
// 処理2
}
else
{
ExitThread( TRUE ); // スレッド終了
}
}
}

void MainProc()
{
// 自動リセットのイベントオブジェクト作成
for( int i=0; i<2; i++ )
{
hEvent[i] = CreateEvent( NULL, FALSE, FALSE, NULL );
}

// スレッドを作成
hThread = CreateThread( NULL, 0, ThreadProc, NULL, 0, &dwThreadID );
}

A 回答 (3件)

>・自動リセットは自動でシグナルと非シグナルを切り替えてくれるものだと思っていたのですが、間違っているのでしょうか?



違います。シグナルを受け取った時に自動的にリセットする(非シグナルに切り替える)だけで、勝手にシグナル状態にはしません。

>初期状態が非シグナルなのでこのまま変化しないということはスレッドはずっと動かないということですか?

そのはずです。

>シグナル状態になったときに制御を返すとありますが、シグナル状態ではなく非シグナル状態になるのですか?

シグナル状態になったから制御を返しますが,返すときにリセット動作する(非シグナル状態にする)だけです。
自動リセットを使う場合は、WaitObjedtて止まっているスレッドを動かすことにあるので、動いてしまえば非シグナル状態にしても問題ありません。

>初期状態に非シグナルを指定していてもちゃんと返ってきます
多分エラーで戻っているのでは。イベント作ったプロセス終了しているように見えますが、問題ないですか?
INFINITEが指定されているのでシグナル状態になるまで戻ってこないはずです。
時間が設定してあれば、タイムアウトで戻ってきますけど。
通常勝手にSetEventが呼ばれることは無いと思います。


>スレッドを使わなくなったときはどっちを使うべきでしょうか?
ExitThread()
CreateThread()についてもう一度読んでください。
これに限らず、たいていマニュアルにあると思いますが。


ちなみに、古いWIN32APIのHELP読んだだけで回答してますので、自信無しです。
他のOSでは似たことやってますし、Windowsでもイベントでなくメッセージでプロセス間WaitForMultipleObjectsは使ったことありますが。
    • good
    • 0
この回答へのお礼

やっと分かってきました。
丁寧に教えていただきありがとうございました。

お礼日時:2003/11/03 07:19

なんらかの同期オブジェクト(例えばイベント)がシグナル状態・非シグナル状態のどちらであっても、スレッドが勝手にサスペンドすることはありません。



同期オブジェクトがシグナル状態であれば、その同期オブジェクトを指定してWaitFor???()を呼び出せば、すぐに戻ってきます。非シグナル状態であれば、シグナル状態になるか、タイムアウトするまで、WaitFor???()から戻ってきません。(呼び出したスレッドはサスペンド状態になり、その間CPU時間は割り当てられない)

自動リセットイベントは、初期状態をリセット状態であるようにします。このイベントを待つ必要があれば、WaitFor???()を呼び出します。別のスレッドが、このイベントをセットすることで、このイベントを待っていたスレッドがWaitFor???()から戻ります(=サスペンドが解除される)。再度このイベントを待つ前に誰かがイベントをリセットしてやらないとイベントの意味が無くなってしまうのですが、このイベントを待っていたスレッドを通過させると同時にイベントもリセットさせるのが自動リセットイベントです。
待つ→セット→待つ→セットの繰り返しだけで同期が取れるようになっています。

シグナル状態=青信号、非シグナル状態=赤信号、信号を見て止まるかどうかは、WaitFor???()の呼び出しと理解するといいでしょう。止まっているものを動かすには、別の誰かが信号を青にしてやる必要があります。

スレッドハンドルは、スレッドの生存状態と同期を取る為にも使用されるので、ExitThread()やTerminateThread()によってスレッドが終了しても、スレッドハンドルは有効です。スレッドハンドルはスレッドそのものでは無いので、スレッドハンドルをクローズしても、スレッドは終了しません。
スレッドが終了しているかどうかに関係なく、不要になったスレッドハンドルは自分でCloseHandle()を呼び出して開放してやる必要があります。(もちろんプロセス終了時には全てのハンドルがクローズされます)
    • good
    • 0
この回答へのお礼

ご回答ありがとうございます。

お礼日時:2003/11/03 07:24

Windowsですよね。

この種の内容はOSによって異なりますのでご注意を。

>○シグナル状態と非シグナル状態とはどういう状態なのでしょうか?

イベントを待つプロセス,スレッドが動作できる状態がシグナル状態、そうでないのが非シグナル状態です。
WaitForMultipleObjects()等でイベントを待っているスレッドなどはシグナル状態になるまで、
実行を止めて待ちます。

>○自動リセットの場合ではどのタイミングで切り替わっているのでしょうか?

SetEvent()がないため、初期状態(非シグナル)のまま変化しません。
もし、どこかでSetEvent()が呼ばれた場合,その時点でイベントがシグナル状態になり、スレッドが動作し、
> DWORD r = WaitForMultipleObjects( 2, hEvent, FALSE, INFINITE );
のWaitForMultipleObjects()の関数から帰る時に、
非シグナル状態になります。

>○手動リセットの場合ではどのタイミングで切り替えればよいのでしょうか?

プログラムの目的、内容等によります。
自動でなく手動にするなら何らかの目的があるはずなので。
特に何もなければ、自動と同じでいいでしょう・・というか、自動を使いましょう。

>○この2つの関数の役割の違いについて教えて下さい。
ExitThread()はスレッドを終了させるためのもので、
CloseHandle() はハンドルを閉じるための物です。
実際の処理内容は異なります。
例えば,ExitThread()が呼ばれてもスレッドハンドルはクローズされない場合があります。

>関数実行時にシグナル状態は気にする必要はありますか?(シグナル状態にしなくてよいのか?

処理内容によります。
まあ、フェイルセーフ,理解を深めるという意味で,常に気にしていた方がいいかも知れませんが。
    • good
    • 0
この回答へのお礼

ご回答ありがとうございます。
でもまだイベントオブジェクトが理解できません・・・

>Windowsですよね。この種の内容はOSによって異なりますのでご注意を。
・書き忘れていました。すみません。OSはWindowsXPです。

>>○自動リセットの場合ではどのタイミングで切り替わっているのでしょうか?

>SetEvent()がないため、初期状態(非シグナル)のまま変化しません。
>もし、どこかでSetEvent()が呼ばれた場合,その時点でイベントがシグナル状態になり、スレッドが動作し、
>> DWORD r = WaitForMultipleObjects( 2, hEvent, FALSE, INFINITE );
>のWaitForMultipleObjects()の関数から帰る時に、
>非シグナル状態になります。
・自動リセットは自動でシグナルと非シグナルを切り替えてくれるものだと思っていたのですが、間違っているのでしょうか?
「スレッドが動作できる状態=シグナル状態」なんですよね?
初期状態が非シグナルなのでこのまま変化しないということはスレッドはずっと動かないということですか?
・MSDNにはWaitForMultipleObjects関数はシグナル状態になったときに制御を返すとありますが、シグナル状態ではなく非シグナル状態になるのですか?
それに初期状態に非シグナルを指定していてもちゃんと返ってきますが、これはどこかでSetEvent関数が呼ばれていると考えてよいのでしょうか?

>>○この2つの関数の役割の違いについて教えて下さい。
>ExitThread()はスレッドを終了させるためのもので、
>CloseHandle() はハンドルを閉じるための物です。
>実際の処理内容は異なります。
>例えば,ExitThread()が呼ばれてもスレッドハンドルはクローズされない場合があります。

>>関数実行時にシグナル状態は気にする必要はありますか?(シグナル状態にしなくてよいのか? )

>処理内容によります。
>まあ、フェイルセーフ,理解を深めるという意味で,常に気にしていた方がいいかも知れませんが。
・どういう時に使い分けをしたらよいのでしょうか?
スレッドを使わなくなったときはどっちを使うべきでしょうか?それとも両方ですか?
質問が多くなってしまって申し訳ございません。

お礼日時:2003/11/02 11:49

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!

このQ&Aを見た人はこんなQ&Aも見ています


おすすめ情報