#pragma twice

KAB-studio > プログラミング > #pragma twice > 283 Version 14.16 スレッドを待ってみる

#pragma twice 283 Version 14.16 スレッドを待ってみる

前のページへ 表紙・目次へ 次のページへ

 Version 14.16
スレッドを待ってみる

スレッドの使い方にはいくつかパターンがあります。今回はそのひとつ、
スレッドが終わるまで待つというのをしてみます
スレッドが終わるまで待つ……んじゃ、スレッドを使う意味がないよう
な……
それはそうなんだけどね、これから複雑な処理をするための準備ってこと

う、複雑なのがあるんだ……
ただ、普通に待つだけなら簡単にできるよ

// 別スレッドで呼び出される関数。
void __cdecl ThreadFunction( void *p_p )
{
    TRACE( "スレッドです。\n" );
    TRACE( "10 秒止まります。\n" );
    Sleep( 10 * 1000 );
    TRACE( "10 秒止まりました。\n" );
    TRACE( "スレッド終了します。\n" );
}

// スレッドを作って呼び出して待つ関数。
void WaitThread()
{
    HANDLE hThread 
        = (HANDLE)_beginthread( ThreadFunction, 0, NULL );

    TRACE( "待機開始。\n" );
    DWORD dwResult = WaitForSingleObject( hThread, 100 * 1000 );

    if( dwResult == WAIT_TIMEOUT )
    {
        TRACE( "タイムアウト。\n" );
    }
    else
    {
        TRACE( "待機終了。\n" );
    }
}   

あ! WaitForSingleObject() だ!
そう、同期オブジェクトを待つときに使った API です。詳しくは 
Version 14.05 ( No.272 ) を参照
スレッドも同じように待てるの?
そう。まず、 _beginthread() の戻り値は、ミューテックスやセマフォと
同じ【ハンドル】なんです
そういえばミューテックスとかもハンドル取得してそれ使ってたね
このハンドルも、同期オブジェクトと同じようにシグナルが変わります

・スレッド実行中:シグナルオフ
・スレッド終了 :シグナルオン

なるほど、スレッドのハンドルを待てば、スレッドが終わるまで待ってい
て、終わったら待機終了、ってわけね
そう、こんな感じに

待機開始。
スレッドです。
10 秒止まります。
10 秒止まりました。
スレッド終了します。
スレッド 0x798 終了、終了コード 0 (0x0)。
待機終了。

 WaitForSingleObject() は他の同期オブジェクトと同じようにスレッド
を待ちます。そして、スレッドは終了するとシグナルがオンになります
なんかホントに同期オブジェクトみたい……あ、そういえば

スレッド 0x1E0 終了、終了コード 0 (0x0)。

って?
これはスレッド終了時のメッセージ。これはスレッドが終了したのを VC 
が検知して勝手に出力してるものだから、気にしなくていいかな
むー、気にしないってゆーのもアレね……
さて、この方法は普通には使いません
そなの?
最初のスレッドが、立ち上げたスレッドが終わるの待ってたら、ただの
シングルスレッドでしょ
そか、それじゃスレッド立ち上げる意味ないね
だから、するとしたら間にもうひとつスレッドを挟みます
へ?

// 別スレッドで呼び出される関数。
void __cdecl ThreadFunction( void *p_p )
{
    TRACE( "スレッドです。\n" );
    TRACE( "10 秒止まります。\n" );
    Sleep( 10 * 1000 );
    TRACE( "10 秒止まりました。\n" );
    TRACE( "スレッド終了します。\n" );
}

// スレッドを作って呼び出して待つ関数。
// ただし、この関数も別スレッドとして呼び出されます。
void __cdecl WaitThread( void *p_p )
{
    HANDLE hThread 
        = (HANDLE)_beginthread( ThreadFunction, 0, NULL );

    TRACE( "待機開始。\n" );
    DWORD dwResult = WaitForSingleObject( hThread, 100 * 1000 );

    if( dwResult == WAIT_TIMEOUT )
    {
        TRACE( "タイムアウト。\n" );
    }
    else
    {
        TRACE( "待機終了。\n" );
    }
}   

// WaitThread() を別スレッドとして呼び出す関数。
// この関数をボタンのイベントハンドラとかで呼んでください。
void CallThread()
{
    TRACE( "WaitThread() 呼び出し。\n" );
    _beginthread( WaitThread, 0, NULL );
    TRACE( "WaitThread() 呼び出し完了。\n" );
}

関数がみっつ……
呼び出す順番はこう

CallThread() :メインスレッド
     ↓
WaitThread() :サブスレッド1
     ↓
ThreadFunction() :サブスレッド2

間の WaitThread() も別スレッドで呼ぶんだ……
これをダイアログアプリで試してみると、ダイアログが自由に動かせるで
しょ
あ、ホントだ! さっきまで固まってたのに
これまでの例のように、メインスレッドでスレッドを作ってそれを待って
いると、メインスレッドが止まったままになっちゃうでしょ
それが、もうひとつスレッド作れば、大丈夫になる……
もう少し実用的な例で考えてみようか

・サブスレッド2の処理を3つ平行に行う。
・3つの処理が完了したらサブスレッド1で残処理をする。

という例を考えてみます
つまりサブスレッド23つが終わったらサブスレッド1でなんかす
る……
こういう場合、 WaitForMultipleObjects() っていう関数を使います

// ThreadFunction() は同じ。

// スレッドを作って呼び出して待つ関数。
// ただし、この関数も別スレッドとして呼び出されます。
void __cdecl WaitThread( void *p_p )
{
    // 3つのハンドル。
    HANDLE hThreadAry[3];
    hThreadAry[0]
        = (HANDLE)_beginthread( ThreadFunction, 0, NULL );

    hThreadAry[1]
        = (HANDLE)_beginthread( ThreadFunction, 0, NULL );

    hThreadAry[2]
        = (HANDLE)_beginthread( ThreadFunction, 0, NULL );

    TRACE( "待機開始。\n" );
    DWORD dwResult
        = WaitForMultipleObjects( 3, hThreadAry, TRUE, 100 * 1000 );

    if( dwResult == WAIT_TIMEOUT )
    {
        TRACE( "タイムアウト。\n" );
    }
    else
    {
        TRACE( "待機終了。\n" );
    }
}   

// CallThread() は同じ。

 ThreadFunction() を3回呼んで……配列に入れてる?
そう、 HANDLE の配列に入れて、それを WaitForMultipleObjects() とい
う API に渡します
 WaitForSingleObject() の複数版、ってこと?
そういうこと。 WaitForMultipleObjects() の第1引数はハンドルの数、
つまり第2引数の要素数。第2引数は監視対象のハンドルの配列
このハンドルを待機するわけね
第3引数は、全部待つか、ひとつだけ待つか。 TRUE だと、すべての
ハンドルがシグナルオンになるまで待ちます
 FALSE だと?
 FALSE だとひとつだけでもシグナルオンになったら待機終了
へー
実際の流れはこう

WaitThread() 呼び出し。
WaitThread() 呼び出し完了。
待機開始。
スレッドです。
10 秒止まります。
スレッドです。
10 秒止まります。
スレッドです。
10 秒止まります。
10 秒止まりました。
スレッド終了します。
スレッド 0x7C8 終了、終了コード 0 (0x0)。
10 秒止まりました。
スレッド終了します。
スレッド 0x3A8 終了、終了コード 0 (0x0)。
10 秒止まりました。
スレッド終了します。
スレッド 0x37C 終了、終了コード 0 (0x0)。
待機終了。
スレッド 0x658 終了、終了コード 0 (0x0)。

ホントだ、サブスレッド2が3つとも終わってからサブスレッド2が待機
終了してる
こういう使い方もできるってことで

/*
    Preview Next Story!
*/
でもなんかいまいち使い道わからない
というわけで次回からさらに具体的な使い方を見ていきます
そっちから教えてもらいたかったなー
スレッドだとそれは危険だから、基礎からこつこつと
えー?
というわけで次回
< Version 14.17 スレッドで変数を共有する >
につづく!
いや、本当にスレッドは危険なんだよね……
何泣いてんの……
 
del.icio.us 登録する
Yahoo!ブックマーク 詳細を表示 users
livedoorクリップ 詳細を表示 livedoorクリップ ブックマーク数
はてなブックマーク 詳細を表示 はてなブックマーク ブックマーク数
RSSに登録
del.icio.us 登録する
Yahoo!ブックマーク 詳細を表示 users
livedoorクリップ 詳細を表示 livedoorクリップ ブックマーク数
はてなブックマーク 詳細を表示 はてなブックマーク ブックマーク数
 
このページは、Visual C++ 6.0を用いた C++ 言語プログラミングの解説を行う#pragma twiceの一コンテンツです。
詳しい説明は#pragma twiceのトップページをご覧ください。