猿にはわからないスレッドの話

「猿でもわかるスレッド講座」ぐらい言えればいいのですがー
まぁ、講座できるほど説明がうまいわけでもないし、詳しいことがわかるわけでもないのでー


「猿にはわからないスレッドの話」ということでw


スレッドを作るのは簡単です、書式を勉強すれば誰でも作り出せます。
難しいというか、ハマりやすいのは、書式は問題ないのに、同期に失敗してバグを生み出すことです。
コレは「共有されているものに、どれぐらい注意できるか?」という単純な話でもあります。
通常のプログラムとマルチスレッドの違いは、プログラムが実行されている流れが1つだけなのか、複数あるのかです。
どこにも共有しているものがなければ、通常のプログラムとなにも変わりません。
複数の実行型を起動している状態と同じですね。(マルチプロセスでの動作ですね。)
お互いに共有するものが無ければ相手のことなど考えなくていいわけです。


じゃー共有するものがあった場合はどうかと考えるとー
そう、例えばファイルに対して書き込みをするプログラムが2つあったとします。
どちらか1つだけが動作している場合は、なにも問題はありません。
この2つのプログラムが同時に動作していても、別々のファイルを扱っているなら問題ありません。
問題が発生するのは、同時に同じファイルを扱う場合です。
対象のファイルがどうなってしまうのか・・・タイミングやプログラムのつくりで様々な結果になりますね。


マルチスレッドってのも同じことです、マルチプロセスと同じことが発生します。
問題は、マルチプロセスが共有しているものは比較的わかりやすいが、マルチスレッドが共有しているものは判りにくいことです。
まぁ、細かいものが共有されているので、見落としやすいってことですね。
より具体的に言えば、「変数」が共有されているからです。
ファイルなどと違って「共有している」という意識が薄くなりやすいんですねぇ。


同期という点でもう1つ。
スレッドの扱いでもっとも難しいと思うのは、スレッドの終了です。
スレッドは開始することよりも終了させるほうが難しいです。
これもマルチプロセスで考えると想像しやすいと思います。
起動したのはいいが、途中で停止(終了)させたい場合・・・いろいろなパターンがありますね。
もちろんプロセスを殺して強制終了させる方法もありますが・・・通常最後の手段になりますよねぇ。


スレッドの終了待ちとしてWaitForMultipleObjectsでタイムアウト指定ができたりしますが・・・
どう処理しているのかで、スレッドに対する理解力がわかると思います。
エラーの1つだと見立てて、そのまま終了してしまうようなコード・・・ありませんか?
CloseHandleして綺麗に終わった気になってませんか?


タイムアウト=処理は継続中


エラーではないのです。
タイムアウトとして終了したいなら、スレッド側に外部からスレッドを停止させる仕組みを入れるべきです。
ちなみに、スレッド実行中でもCloseHandleは正常終了します。
ハンドルは閉じられますが、スレッドはそのまま継続するんですねぇ。
なんか、あまりにも堂々とタイムアウト後にCloseHandleして終了しているサンプルをみてー
「あれ?スレッドも強制終了するのかな?」とか思ってしまいましたが、そんなことは当たり前のようになかったですw


もちろん、プロセスの終了時にはスレッドも強制終了するんですが・・・
mallocしてfreeしないってなものとは全然違うわけで・・・
ファイル操作するようなスレッドとかだと結構泣けることになりそうですねぇ。
スレッドを扱う場合は、そのスレッドがいつ終了するのかということにも注意しましょうって話です。


PS.
CloseHandleで閉じたハンドル変数にNULLを代入しないと駄目ってな話・・・ガセだと思うんだけど、どうなんだろう?
C#とかのガベージコレクションのイメージなんですかねぇ。
少なくともC++でNULLを代入しておかないといけない理由がみつからない。
あるとしたらハンドル変数がNULLなら、ハンドルを使用していないという設計で作成しているような場合だと思うんだけど・・・
ガセだよーとか、こうかもーみたいな意見があればコメント欄で教えてくだされー。
まぁ、ソレ書いた本人が守ってないようなものだからなぁw

マルチコアとスレッド数

マルチコア時代だからこれからは、業務システムでも並列処理をしないと駄目ってな意見を見ると思うのはー
「どこで並列処理をつかうの?」
という素朴な疑問だったりします。
並行処理と並列処理を区別せずに表現している場合は、並行処理ならば、まだわかります。
ライブラリの進化で並行処理の扱いが簡単になり、「本当は並行処理させたほうがいいんだけど、そこまで力を入れる必要がない」ってな理由で使わなかった部分での採用が進むってな話は理解できます。
この辺、楽に使えるならカラフルなボタンを採用して見栄えをよくしたいってな話に近いものがあるかもしれませんねぇ。


・・・で、並行処理ならばコア数なんて意識する必要性はほとんどないでしょ?
並行に処理したいってのが最大の理由で採用しているのですから、コアが1つだろうが2つだろうが関係ないわけです。
そりゃー並行に動いている以上のコアがあればパフォーマンスは良くなりますが・・・
その逆、つまりコアがN個だからN並行にしようってのは順番がおかしいというか、並行に動作する数に自由度がある時点で別の発想になるのではないかと。
例えばサーバーで複数のユーザーを同時に処理したい場合、コア数に合わせて最大同時処理数を制限することは可能だと思います。
・・・が本当にそんな制限かけるのか?って話になると微妙じゃないかなと。


コア数を意識するのは、並列処理になりますね。
並列処理は、コアが2つ以上あってはじめて価値が生まれます。
で、このときスレッド数をどれぐらい意識するかというと・・・あまり意識しなくてもいいというか意識しても意味がないと思うのですよ。
N並列だと設計したら、コア数はN個以上ないと駄目なわけです。
コア数なんてものはハード依存するのですから、ハードを決めうちする以外、設計時にNという数は決められない。
また、コアがN個存在していたとしても、実行時に全てのコアが空いているかどうかもわかりません。
実行中に別のプログラムが起動することでコアの状況なんて簡単に変動します。


つまり・・・いくら考えても最適なスレッド数なんて決定できないわけです。
搭載されているコア数全てを使えるものだと仮定して、スレッド数を自動設定するものが多いんじゃないかなぁ?
もしくは手動でスレッド数を指定できるようなものですね。


話を業務システムに戻すと、並列処理させてお得なとこってどこですかね。
サーバーは同時処理しないといけないことが多いだろうから、並行処理が前提で、コア数依存する並列処理はパフォーマンスを発揮しにくいのではないかと思います。
スレッドプールの上限として考えても現在のコア数では少なすぎるかなと。


じゃークライアントはどうかと考えるとー
単独で動作するクライアントなら自由に使えるので並列処理の出番はありそうですが、業務システムで単独動作が多いかというと・・・少ないんじゃないですかね?
また、排他処理の関係などから並列処理できる部分も限定されると思うのです。
そんなことを考えるなら各種エンジン(データベースとかフレームワークとか)が並列処理を担当し、プログラムのほうは並行処理に専念したほうが、効果的のように思えます。


どこか1つが並列処理を前提としているのなら、他の部分はそれを邪魔することしかできないんですよねぇ(^^;

気分転換

シルバーから動かない日々を過ごしているわけですが、気分転換をかねてシナリオモードの実績取りを進めてみました。
シナリオモードは難易度が4段階あって、一番簡単なモードでクリアだけはしてありました。
主にマルチで遊んでいたからってのも大きかったんですが、難易度の違いに興味がなかったので放置してました。


いやー難易度変わると結構ゲーム変わっちゃいますねw
実績取るにはクリアするだけじゃなくて、特定の条件を満たす必要があるのですが、これが結構難しい。
下から2番目の難易度は比較的簡単ですが、その上が難しい(^^;
一番難易度が高いモードは、そのような実績が存在していないので、クリアするだけ、こっちのほうが簡単。
いや、簡単といっても、はじめたばかりのころじゃクリアできてないと思うぐらいなんですが(^^;
まだ序盤だから・・・これ先に進むとクリアだけでも難しいかも(^^;;;;


これはコレでパズル解いているようで、結構はまってたりしまw

ゴールドへの道 その2

いまだにシルバー脱出できず。
勝ちパターンと負けパターンがさらにはっきりしてきた。
生産から意識を抜かない場合が勝ちパターンになることが多いです。


Zergの場合、拠点に生まれる幼虫は、なにもしなければ最大3匹で停止してしまう。
常に生産に意識を向けないと、カウンターが痛い。
それは攻撃中でも意識してないと駄目なんですよねぇ。
資源を抱えて負ける場合は、そこができてないわけで(^^;


あと、偵察も弱い感じ。
いまだに即Bansheeとかでハマる自分が悔しい(^^;
油断していると2ndにCannon建てられてる場合もーーーー
いや、偵察でCannonだと判っていたんだけど、防衛用だと思い込むと危ないわけで・・・


対ProtossもImmortalを見る場面が増えて面白くなりましたね。
前は、StalkerからColossusに繋げるだけの人が多かったけど、それじゃRoachにやられてしまうことが増えたんですよねぇ。
お互い、偵察してどうするかを判断しないといけない場面が増えて面白いです。


まぁ・・・そんな感じで、いつものように、はてなスターを押しにいくわけですが(T_T)

ゴールドへの道

ゴールドの壁が高い高いw
シルバー上位で上がったり下がったりを繰り返してます。
カウンター食らって拠点壊滅するのが負けパターン。
資源がいくらあっても、兵隊つくれなくなるから当たり前なんだけど、Zergだと守るのが難しい。
そもそも資源が残っているということは、それだけ兵隊作れてないってことなので、そこが間違ってるんだが(^^;


Roachを作るかどうか、数をどうするかってのが課題かなぁ。
Banelingを適当に当ててどうにかなるのは前半だけで、敵の数が増えると当てるまえにいなくなる。
使い捨てなので、作りすぎると他のユニットが作れないから数のバランスが難しい。
ただ、はっきりわかったのは、やるならやるで大量に作って一瞬で粉砕しないと駄目ってこと。
HPが1でも残れば攻撃力はそのまま残るわけで、その当たり前の差が大きな差として残ってしまう。


Roachは壁として優秀で、他のユニットと混ぜることで効果が大きくなる。
Marineしか出さないようならRoachでもいい感じだったが、本格的に対応したことないので実際問題有効なのかどうかがわからない(^^;
素直にMutalisk作ったほうが強いような気もするんだが、Mutaliskは数揃えないと弱い弱い(^^;
資源も大量に食らうので、安定するのは安価なZerglingとのコンビ。
Zerglingは本当に優秀なユニットで、まさに数の暴力・・・範囲攻撃ユニットがでるまでの間ですが(^^;
同じZerg相手だと本気で強いんだけど、相手も同じもの持ってるからなぁw


Infestorは結構好きだし、強いんだけど扱いが難しいw
何ゲームかはInfestorで拠点を襲って勝たせてもらったが、これ通じるのはもうZergぐらいなんだよなぁw


しかたがないので、今日もはてなスターをポチポチする仕事に戻りますw

StarCraft2 その4

いやーゴールドの壁なかなか越えられません(^^;
シルバー入って連敗したけど、やっとなんとかなるようになってきた感じ。
バランスパッチがあたりましたが、自分のレベルだとテランのタンクダメージが軽減されたのが大きい感じです。
プロトスのジーロットは・・・少し楽になった程度ですかね(^^;
いまだに本気のリーパーラッシュは見たことがないので、リーパーの変更が大きいのかどうかは判断できないです。


しかし・・・シルバーで自分と同じザーグに遭遇すると、相手が高確率で6poolなのがなんとも(^^;
プロトスのストーカー大量に作る戦法に出会うのが多いんだけど、コロッサスまで出始めると高確率で負ける。
中盤まではそれなりに戦ってるんだけど・・・基本防戦になってるのが(^^;
こー相手に兵を貯めさせては駄目なのはわかるんだけど、押し切れないんだよなぁ。
常に先手を取って戦えるようにならないとゴールドにはなれないかもしれないと思う今日この頃。


仕方がないので、某所ではてなスターをポチポチ増やす作業を混ぜる日々w

StarCraft2 その3

やっとこさ、シルバーリーグに突入。
いきなり6位スタートだったけど、そんなものなのか(^^;


ガスとミネラルの取得バランスは結構重要ですねぇ。
必要な時に、必要な分だけ確保するという当たり前のことなんだけど、少しやり方を変えただけで、勝率が一気に変わりました。
ブロンズで連勝できるようになったところで、シルバーリーグに昇格。
レベルが同じぐらいな人とマッチングされることが多いから、凄くよくできてます。


だからだろうか・・・リーパーハラスやヘリオンハラスなど、有名どこの攻撃をほとんど受けたことがないのは(^^;
これから見かけるのか、それとも小技ではなく、物量に移行するのか、シルバーリーグも楽しみです。
ゴールドへの道は遠いんだろうなぁ(^^;;;;