ThreadPool QueueUserWorkItem

さて、気温は30度を越えようやく夏らしくなって参りました。
私の通う仕事場の室温も順調に28度を越えています‥暑くてプログラムなんか組んでられないっス。
エラそうに他人の作業に口を出すだけなら快適な温度かも知れませんが!


‥まあそれはともかくWindows2000以降、QueueUserWorkItemというAPIによってThreadPool機能が提供されています。
MSDNを読んでも殆ど意味不明なことが書いてあり、利用を躊躇してしまうようなドマイナーAPIみたいですが、実際には結構使えそうです。え?知らなかったのオレだけ?w


MSDNには「必ず他のヒントと組み合わせて使ってください」と書いてある、スレッドを積極的に生成するというヒント「だけ」を第3引数に与えるのがミソのようです。
強制的に管理用のワーカースレッド(と思われる)が1つ、プロセスに付帯します。
さらに最大500(つまり501)スレッドまで勝手に生成され、その後仕事を与えなければ45秒くらいでどんどんスレッドは減少していく挙動です。
簡単に調査しましたが、ひたすらそれを繰り返してもリーク等は無いっぽいです。


私はスレッドを起こす場合の最大数などの制御ができないという理由から自前のThreadPoolを書くことになりましたが「1プロセスで500スレッド?ケチケチしないぜ」「ThreadPool以外でスレッドなんて殆ど起こさないッス」という方は積極的に使うと幸せになれます。
恐らく内部はメッセージ通信とそのキューイングで動作しているので、多重のスレッドコンテキストからQueueUserWorkItemのワーカースレッド上限数以上を叩いても特に問題はないようでした。
未処理の仕事が10000個以上に到達した瞬間だけエラーになるんじゃないかなあ、と予想してみたり。


スレッドを積極的に生成するヒントのみ以外も与えてしまった場合は、ワーカースレッド1つだけで頑張るモードになります。
ひたすらQueueUserWorkItemで積まれたコールバックをシーケンシャルに呼び出すパターン(非I/Oブロッキング)と、コールバックをシーケンシャルに呼び出し続ける中で、何らかのメッセージ待ち(例えばSleepではなくSleepExのような待ちね)が発生した時には次のコールバックを呼び出すパターン(I/Oブロッキング)の2種類が有ります。
ま、どちらのパターンも使いづらいというか、事実上あんまり使えません。
特にI/Oブロッキングの方はコールバックが入れ子状態に呼ばれまくる可能性がある(MSDN再帰問題に注意しろと云うのはこのコトを意味しているらしい)ので、あまり安心して使えません。


Vistaからはもっと具体的な制御を含めたThreadPool APIが沢山用意されているみたいですが、必要最小限シンプルなのでQueueUserWorkItemも悪くないかと思いましたヨ。