スレッドプールからのイベント呼び出し

スレッドプールからのイベント呼び出しを行う場合、そのイベントによって呼び出される側のハンドラは

当然スレッドセーフでじゃないといけない。

でも、場合によってはスレッドプールのワーカースレッドではなくて、メインのスレッドで処理したいハンドラも出てくる。

毎回スレッドセーフにするのも面倒だからね。


この場合、スレッドプールには、たとえばWindowsのEventオブジェクトを渡しておいて

処理終了時にシグナルにしてもらうなどの方法が思い浮かぶけど

この方法だとメインスレッドはイベントを登録したクラスごとにEventオブジェクトを毎回調べるために

Check関数を用意してプーリングして呼び出さないといけなくなる。

while(1)
{
	window.checkEvent();
	file.checkEvent();
	socket.checkEvent();
	...


これも結局面倒だよね。ってことでAPCキューを利用するのお勧めです。

windowsのスレッドはAPC(Asynchronous Procedure Call)キューと呼ばれるキューをもってます。

そのキューに関数を登録しておいて、スレッドが警告可能な状態(アラート可能な状態)になると

登録されている関数が実行されるという仕組みです。


警告可能な状態ってのは何かって言うとスレッドが一瞬でも待機する状態です。

このネーミングもどうかと思いますが・・・

これは、たとえばSleepEx,WaitForSingleObjectEx,WaitForMultipleObjectsExなどを使います。

待機するのでパフォーマンスが心配するかもしれませんが

これらの関数はAPCキューに登録された関数がなければ、そのまま指定された時間で処理が帰ってきます。

『SleepExとQueueUserAPCの割り込みパフォーマンス』
http://www.cycleof5th.com/tips/index.php?date=2007-07-13&lang=en

さらに、上記のサイトをみると詳細がわかりますが、そこまで悪くなさそうです。


さて、ワーカースレッドのほうメインスレッドのAPCキューに関数を登録することになりますが

QueueUserAPCというAPIを使います。

これはまぁ・・ぐぐってください。そのままですので分かるはずですしw


この方法のメリットはどのクラスで登録されてもプーリングの処理が同じというところでしょうか。

while(1)
{
	SleepEx(0,TRUE)
	...


たったこれだけでどんなクラスでもワーカースレッドからのinvokeを受け取れますので便利ですよー