2008年07月22日

スレッドとタイマーとイベント その2 完了ルーチン専用スレッドを作る。

別スレッドで待つ場合完了ルーチンはWaitForSingleObjectExで待つのがいいのかと思ったが
QueueUserAPCを外部から送ればよいことに気がついた。
ここまででやったスレッドの生成と開放についてちょっとまとめてみた。
基本的に変数はグローバルかグローバルにポインタかハンドル変数をもつ
ローカルヒープを使う予定なので変数に関するタイミングはいい加減でも良いと思っている。

スレッドの主目的は「待機」と「ブロック」「タイミングの面倒なもの」の3つではないかと思う。
待機を実装する場合イベント待ちが一般的だがAPCキューへのポストの方が使いやすい。
ブロックする命令を実行する場合はその都度スレッドを作ってよいと思う。

別スレッドを作る一番手っ取り早い命令は「TimeSetEvent」でこの関数は後処理などもいらない。
但しTimeSetEventはスレッドを1つしか作らないのでブロックすると再呼び出しできない。
しかし複数を同時に動かすことが無い場合これの命令の便利さを知っておいて損は無いだろう。
とにかく使いやすい。IDすら保持する必要は無くコールバックだけ用意すればいい。

スレッドについて正式に作成する命令はいたってシンプルだ。

コールバックは


function Thread_func1(param:Pointer):LongWord; stdcall;


作成はハンドルとID収納用の変数を用意して

ThreadProc:=@Thread_func1;
m_object[3]:=CreateThread(nil,0,ThreadProc,0,0,w_id1);

でいい。
IDを使わないならばw_id1は捨て変数でよい。

スレッドを閉じるには

CloseHandle(m_object[3]);

とする。

従って動的なスレッド生成の場合は

if m_object[3]<>0 then CloseHandle(m_object[3]);
m_object[3]:=CreateThread(nil,0,ThreadProc,0,0,w_id1);

とする。

スレッドの関数内ではExitThreadで終了するということになっているが省略してもいいらしい。
ExitThreadでスレッドを終わらせてしまってもスレッドそのものは残るので
再度処理をスタートさせる場合は上記のように一旦閉じて再作成することになる。
レジウムなどは権限の設定が必要であり汎用性が無いので
むしろコールバックの中でループとフラグで処理をするのが良いと思われる。

イベントは

m_object[1]:=CreateEvent(nil,false,false,nil);

のように作り、closehandleで処理する。
2番目の値がFalseのときはシグナルになった後自動リセットする。

次のコードは2つのイベントで動作制御しAPCを考慮した待機ルーチンのサンプル。

スレッドはm_object[3]に作られている。
Thread_Flgという変数を用意して$ffなら終了
0以外ならば待機をはさんだアクションを行う。


function Thread_proc0(param:Pointer):LongWord; stdcall;
begin
Thread_Flg:=0;
while (Thread_Flg<>$FF) do begin

WaitForSingleObjectEx(m_object[1],$FFFFFFFF,True);//INFINITE

if Thread_Flg= $ff then Break;
if Thread_Flg= 0 then continue;

ThreadWaiting(ThreadParam1);

WaitForSingleObjectEx(m_object[2],ThreadTimeout,true);
ThreadAction(ThreadParam2);
end;

ExitThread(m_object[3]);
end;


ThreadWaitingとThreadActionは独自定義の実行型変数、デフォルトでは何もしないdefTproc1をアサインしている。
m_object[1]、m_object[2]はイベントだがThread_Flgが0のままだと
ずっと待機してAPCキューにアラートが入るとcontinueして頭に戻る。

このイベントを使った待機スレッドを作ったのはtimeSetEventでSetEventの動作がみたかったからだが
timeSetEventでSetEventを使う形にすると単にフラグのオンオフしか出来ず不便だ。

そこでAPCキューに何か送れば待機から抜けるのであれば
単なるイベントは無くても良いといえなくも無い。
この場合特殊ケースはタイマーをセットする用途のみだ。
そしてそのタイマーもAPC内に記述すればいいので待機ルーチンは以下のようなものでよいことになる。


function Thread_proc1(param:Pointer):LongWord; stdcall;
begin
Thread_Flg:=0;
while (Thread_Flg<>$FF) do begin

SleepEx($FFFFFFFF,True);//INFINITE

end;

ExitThread(m_object[3]);
end;


APCルーチンでExitThreadを呼ぶこともできるわけだから実際はThread_Flgも無くていい。
このスレッドを最初に作っておきWaitableTimerを呼び出す関数など用意しておけば
QueueUserAPCでタイムアウト実行やブロック命令終了後のコールバックなどを実行してくれる。
無論処理が長くなればつまることはいうまでも無い。

とりあえずこれで動的なスレッドの生成と待機用のスレッド生成などが選択肢に入った。


ラベル:CreateThread APC
posted by Xo_ox at 00:48| Comment(0) | Win出直し | このブログの読者になる | 更新情報をチェックする
この記事へのコメント
コメントを書く
お名前:

メールアドレス:

ホームページアドレス:

コメント:

認証コード: [必須入力]


※画像の中の文字を半角で入力してください。
×

この広告は180日以上新しい記事の投稿がないブログに表示されております。