コンテキストについて調べてみた
(2016/02/14 リンクミス修正)
いろいろ、調べていたら2日ほど更新が止まってしまいました・・・
内容は素人の書いている内容なので保証しません・・・
ちょっと恥ずかしいことも書いちゃうかもしれない。
今、やりたいのはC#でそれなりに保守が容易な複数ステートマシンの協調実行の実装技術を獲得するということ。
私のC#の時間は、C#2.0で止まっていて、1年くらい前から再び動き始めた・・・
最初は、Windows FormとWCFで復帰して、半年前にWindows Formじゃ駄目だと、WPF+MVVM+ReactivePropertyを始めて今に至る。
Reactiveプログラミングでも非同期の話題は良く目にするので、
「昔は論外だったけど、今ステートマシンを実装するならどの水準まで出来るのか?」
「Taskとか、async/awaitとか基本的には昔と変わってないのでは?」
というのを仕事抜きでも確認してみたかった。
元々、自分は電気/ファームウェア屋だった。(大学の専攻は違うけど・・・)
組み込みシステムと言えばステートマシンなので、状態遷移図や状態遷移表と実装の間には大きな溝があるというぐらいは分かってるつもり。
少なくとも、口が裂けても、
「UMLでステートマシン図書けたから後は実装するだけでしょ」
なんては言わない。
そもそも、殆どのケースで、
- 状態遷移図や状態遷移表に時間的概念は無く・・・
- 一瞬で遷移前の全ての状態変数と入力を読み取り・・・
- 一瞬で全ての状態変数と出力が再計算され・・・
- 一瞬で遷移後の全ての状態変数と出力が確定する・・・
組み込みやソフトウェアで扱っているCPUでシーケンシャルに実行されているプログラムが、こんな時間の概念のない世界で動いているのか?
答えは「No」ですよね?
「特定のお客さんのところだけで、1年に一回止まるんですけど・・・」
「ちょっと書き換えたらソコソコの確率で不具合が再現してたのにログ収集レベル上げたら再現しなくなったんですけど・・・」
「たまに状態遷移表にない状態変数の組み合わせパターンになる。まるで小人が悪戯して気まぐれで書き換えてるみたいですけど・・・」
とか、経験ないですか?
そんな訳で、
「C#では最新のステートマシンの実装技術や非同期プログラミングの勉強しなきゃ」
と思う今日この頃・・・
マクロレベルのステートマシンの技術はWindows Workflow Foundationとかが、SharePoint Serverの絡みで、特に海外での実績は高そうだけど、WF 4.0でステートマシンが消えて途中で復活したり、国内ではイマイチ情報が少なくて、どうなんだろう。
まあ、取りあえずステートマシンは置いておいて本題に・・・
非同期とかいろいろ調べていると、「コンテキストスイッチ」という言葉がよく出くる。
そう言えば、
「『コンテキスト』って良く目にするけど、フィーリングだけでスルーしてた」
調べていくと、まず「OSS教育シラバス」というのに行き当たった。
表の「学習ガイダンス」をクリックするとコンテンツが読める。
何かの講習会のダイジェストっぽいけど、キーワードを仕込むための、斜め読みにはちょうど良い。
キーワードがヒットした最初のコンテンツは組み込み向けの情報。
26. 組み込みアプリケーション開発に関する知識 I | 日本OSS推進フォーラム
しかし、自分は今時のOSカーネルとかには疎いのでこっちの方がかえって助かる・・・
Linuxの話だとこちら・・・
6. Linuxカーネルに関する知識 I | 日本OSS推進フォーラム
6. Linuxカーネルに関する知識 II | 日本OSS推進フォーラム
他に、ヒットしたのはLinuxの話だけど、こちらのスライド。
www.slideshare.net
ちなみに、スタックの動きとかは、内容はともかくこっちのスライドの最初の方がイメージしやすい (自分は要らない情報だけど)・・・
やっぱり、CPUレベルまで落とし込むと直感的で分かりやすいよね。
ざっくりとまとめると、
- コンテキストスイッチではCPUレジスタ一式やスイッチするコンテキストの種類に応じた構造体を丸々スタックに退避してプロセッサで実行するプログラムを切り替えること
- プロセスの切り替えにはコンテキストスイッチが伴う
- スレッド(組み込みだとタスクという言い方をする)の切り替えにはコンテキストスイッチが伴う
- システムコールにはコンテキストスイッチが伴う
- ハードウェア/ソフトウェア割り込みにはコンテキストスイッチが伴う
- プロシージャコールは含んでいない感じ
- プロシージャコールで部分的にレジスタをスタックに積むのとはコスト(消費CPUクロック)が違うというイメージで良いのかな?
- アプリケーションドメインは.NETの範疇なのでここ(OSS)では扱われていない(保留)
これは、ハイパースレッディングで論理プロセッサがある場合も基本的に同じ。
ただし、各コアの2スレッド目はCPUの機能をフルに活用できないから、同じプロセッサ数なら物理プロセッサが多いCPUの方が早い。
Windows系の話だとこちらに面白い読み物がある。
ざっとさらってみると・・・
ちょっと古いけど、当時から言われていたことを簡単にまとめると・・・
「クロックを上げて高速化を行っていた時代はソフトウェアプログラマはマルチスレッド化さえすれば良かった」
「クロックを上げて高速化を行なう時代は終わった」
「マルチプロセッサ時代はコンテキストスイッチを頻発させたらプログラマの負け」
「プロセスよりAppDomain、AppDomainよりスレッド、スレッドも作りすぎない」
「つまり何でもかんでもマルチスレッドにすればよい時代は終わった」
まあ、ぶっちゃけ言うと、
「そろそろマルチスレッド・・・と呑気にしている間に事情が変わっているのにも気づいていなかった」
「Taskとか、async/awaitとか基本的には昔と変わってないのは言いすぎだった」
ってことになる。恥ずかしい限りです・・・
もちろん、
「シングルスレッドのプログラムを少しだけマルチスレッドにするのは多分OK」
「それでも、状態遷移図や状態遷移表と実装の間には大きな溝がある」
なので、ちょとだけ非同期プログラミングしてみた程度は大丈夫とざっくりと判断・・・
まず、岩永大先生/じんぐる大先生のこちらの記事で仕込みをしてみるかな・・・
同期コンテキストとか、実行コンテキストとか、ここにも「コンテキスト」が出てくる。
async/awaitと同時実行制御 | ++C++; // 未確認飛行 C ブログ
実行コンテキスト | ++C++; // 未確認飛行 C ブログ
非同期処理とディスパッチャー | ++C++; // 未確認飛行 C ブログ
RxとかTPLの解説もある。
C++だとTBBってのがありますね・・・
Intel® Threading Building Blocks (Intel® TBB) | Intel® Developer Zone