ホームページにおける自己紹介

自己紹介とは、自分の事を理解してもらうためにある。
何に役に立つか理解してもらうためにある。

会社の自己紹介は、会社の現在、未来、過去についての記述が成されなければならない。

現在は、業種な何で、今は何をしている会社か。ミッション(使命)と理念は何か。
ミッションとは、・・・・誰に対して、または、何に対して、どんな価値を提供するのか、どんな貢献をするのかを明文化したもの。
理念とは、どうありたいかという理想像。

未来は、ビジョン。
ビジョンとは、これから将来、どうなりたいかという未来像。例えば何をする会社になりたいか。

過去は、社歴と創業の精神。ミッションや理念が生まれたエピソードなど。

そして、これら記述した会社の現在、未来、過去に対しての説明を、社長の「ご挨拶」として掲載する。

次、現在の会社の組織図。規模(資本金など)、本店および各支店の連絡先と位置情報(地図、住所、電話番号、メールアドレスなど)


個人の履歴書との関連も書こう。

死にたいという気持ちとは

 死にたいという気持ちとは、困った事があり、心が弱くなり、自殺の事を考え始めるのが、その気持ちの始めだろう。
心が元気だと、普通、誰もが死にたいという気持ちが発生しなくなる。
たとえ精神病患者だとしても、心が元気だと発生しない。
対策は、分からないが、ただの優しさだけじゃ物足りないだろう。
一緒に、遊んであげるのが、1番の対策になるんじゃないかな。
すると、死にたいという気持ちを忘れ、元気を取り戻すだろう。

ただ、一度、死にたいという気持ちを持ったら、元気な内は問題ないが、元気でなくなったら、再発して、また、死にたいという気持ちを持つようになるだろう。
一度、折れた枝は、つながっても、また、同じ所が折れやすい。

大事な事。笑顔の元気だ。
笑う事。元気が出るようになる。
ふざける事はあまり良くないが、バカ話をして笑い合えたなら元気が復活する。

自殺の事を考える前に、
◯ 精神病ならば、神経科へ行って早く治す事。
◯ 困った事は、誰かに相談して解決する事。(命の電話などで、解決してもらう事も方法論の一つだろう。)
◯ 喜劇を見る事。お笑いを見る事。ふざける事を楽しむ事。自我を忘れるような興奮をする事。そうやって、元気を取り戻す事。しかし、誰かを苦しめるためにふざける事は良くない事だ。

私は、本当の自殺を経験していないが、経験したら死にたいという気持ちから絶対離れられなくなると思う。
だから、考えたくない。その考えから遠ざかりたい。

死にたいという呪いの解除

死にたいという気持ちに理由があると思っていたが、理由が無い事がはっきりしている。

死にたい。死にたく無い。お父さん。お母さん。神様。そういう言葉でぐるぐるしていたが、そこが、また、辛い。

死は罰か。死は罪か。死を超えるものは何か?それは、罪。

罪を無くそう。罪を消滅させよう。いいや、罪を浄化しよう。罪を清めよう。

死にたい→罪を無くそう→罪を清めよう。→生きよう。→神と共にあろう。(理由はいらない)

罪とは何か?悪いことか?それは殺人や不正の事か?いいや、神を信じない事である。
モーゼの十戒を守る事以上に大事な事とは神を信じる事である。
これ一つが十に勝る。

だから、呪われた言葉を唱えるのを次のように変える。

死にたい 死にたい 死にたい(の繰り返しを)
→ 罪を消滅させよう 罪を消滅させよう 罪を消滅させよう
→ 罪を清めよう 罪を清めよう 罪を清めよう。
→ 罪をはらいたい、清めたい、はらいたい、清めたい。(の繰り返しに変える)

すると 死んで地獄へ行くという妄想が、生きていても死んだ時でも、神と共にあるという気持ちに変わって行ける。

生きるために必要な世界観

お母さんが生きている。
お母さんに会いに行こう。
お母さんに会いたいと念が通じる様に祈る。


母が死んで自堕落に生きる私。
私が一番元気になる言葉を虚から発してみよう。
「お母さんが生きている。お母さんに会いに行こう。」
どうやれば、母に会いに行く事ができるか・・・・
「お母さんに会いたいと念が通じる様に祈る。」

念ずるの始めとは、近づきたいと願う事。
祈りの始めとは、会いたいと念ずる事。


私が生きるために必要な宗教的世界観は、ここから始まる。


著書題名「ワンさんの洗礼 霊能者たちの集まる教会にて」(文芸社)著者:吉田作太郎
発売中。
https://www.amazon.co.jp/%E3%83%AF%E3%83%B3%E3%81%95%E3%82%93%E3%81%AE%E6%B4%97%E7%A4%BC-%E9%9C%8A%E8%83%BD%E8%80%85%E3%81%9F%E3%81%A1%E3%81%AE%E9%9B%86%E3%81%BE%E3%82%8B%E6%95%99%E4%BC%9A%E3%81%AB%E3%81%A6-%E5%90%89%E7%94%B0-%E4%BD%9C%E5%A4%AA%E9%83%8E/dp/4286188280


死ぬのが怖い。
死にたいと思っている時は、自殺の方法を考え、それを実行する事を考える。
そこまでだ。
死ぬのは怖いという恐怖感は、死んだ時の意識を考える。
そこには身動きのできない自分がある。
息が止まった、そして、全身が束縛されている自分を想像する。
それは、怖い事だ。

神は不滅だ。

人生とは、挫折の連続である。その挫折から回復させるのには「根拠の無い自信」が必要だとインターネットで見た覚えがある。
根拠の無い自信。それの反対用語は根拠のある自信である。
根拠のある自信とは、数値化できるだとか客観視できる事柄により裏付けられる自信である。
根拠の無い自信とは、神に愛されているなどがそうである。
神を信じている人には悪いが、神という存在は、絶対だとも言えるが、実は一番根拠の無い存在である。
魂、霊魂も根拠の無い存在である。

さて、実は、最近の私は、「死にたい」と思っているのである。
両親が死んで寂しいという気持ちを持っていたが、なぜか、「死にたい」と思ってしまっているのである。
経済的に困っている事が無いのに「死にたい」という願望を持っているので、実に贅沢な悩みなのである。
私の本心は「死にたくは無い」である。経済的にも身体的にも困っていないから。
だから、「死にたい」という気持ちは、死神から目を付けられているのではないだろうかと考えるのである。

さて、この状態から脱出したい。
どうやって、この「死にたい」という気持ちから脱する事ができるようになるのだろうか。

そこで、根拠の無い自信の出番である。
スローガンとして、「神は不滅だ!!」を三べん唱えてみる。すると気合が出てくるではないか。
ニーチェが「神は死んだ」と言ったが、そのアンチテーゼである「神は不滅だ!!」を気合を込めて唱える。
霊魂は、不滅かそうではないかという議論があるらしいが、「神は不滅だ!!」を唱えてみる。
すると根拠の無い自信が出てくるのである。

自殺を考える時は、自分が消滅する事を考える。消滅したくてどうしようもない状態になる。
この消滅に対して正反対の絶対的存在をイメージするならば、絶対的な神の存在をイメージした方が良いだろう。
キリスト教では、「神は愛だ!!」という事になるだろうが、現在、自殺を食い止めるには、「神は絶対だ!!」、「神は不滅だ!!」をイメージして唱えて、気合を入れる事が肝要となる。
生きるためには、気合が必要である。
根拠のある無常な存在から出てくる自信からの気合は無常で有限であるが、根拠の無い絶対的な存在から出てくる自信からの気合は絶対的で無限であろう。

だから、理由はいらない。
神は不滅だ!!神は不滅だ!!神は不滅だ!!

私が、若い時は、「自分が嫌いだ」という自虐的感情を持っていたが、死にたいとは思わなかった。
今は、「自分が嫌いだ」という感情を持っておらず、むしろ「自分が好きだ」というポジティブシンキングである。
「自分が好き」なのに、「死にたい」というのは、なんか、贅沢な悩みである。


さて、気づいた事がある。
「死にたい」という感情の時は、うつ病なのである。
このうつの時から、躁病に変わる時、「死にたい」という感情のままだと、躁病の勢いで「自殺」する事になるのではないだろうか。つまり、感情の「うつ」から「そう」に変わる時の過度現象の時が危ない。

8月14日 さびしくてたまらない気持ちになった。それは、死にたいという気持ちになった時と同様であった。そうか、死にたいほど寂しいんだ。寂しいという気持ちはこんなにも切なくつらいものなのだなぁ〜。そこで、仏壇の水を取り替え線香をあげお経を唱えた。

仲間は最大の敵である 著者:吉田作太郎

初級哲学の本「ソフィーの世界」で、ダーウィンの進化論を読んで理解した事とは、「仲間は最大の敵である」という事だ。
生物学用語の種。種にとって一番の敵とは天敵の存在ではない。同じ餌を奪い合う仲間こそ、種にとって最大の敵なのだ。
こう、私は、ダーウィンの進化論を理解した。
こう思い悩みながら、私は、色々な人に、「仲間は最大の敵だと思いますか?実はダーウィンの進化論ではそのようになっているのです。あなたがたの人間関係では、どうでしょうか?」などと質問したら、「そうだと思う」という返事が多かったのである。
高校の倫理社会の教科書を読むと、トマスホッブスは、次の様な事を言った。「万人の万人に対する闘争」
つまり、人間社会は、「仲間は最大の敵である」という事らしい。
それは、もっと簡単に言うと、「人間とは、仲間同士、足の引っ張り合いをしている。」と言う事である。
そこでの解決策とは、「徳のある王様は、神様から人を支配する権限を与えられている」(王権神授説)これ解決策。

孔子は言いました。「君。君たり。臣。臣たり。親。親たり。子。子たり。」
君主は、臣下にとって親の様な存在。だから君主は偉い。それは、天が定めた理り。
そして、これが、孔子が言う権力の意味である。

サラリーマンの愚痴で、上司の悪口を言う人に対して、私は、「出世して権力を得なさい。」とアドバイスするのは、仲間が最大の敵であるからだ。
キリスト教の罪の中で、妬み、僻み、嫉妬。これ、仲間が最大の敵である証拠である。

ダーウィンの進化論の仲間は最大の敵である。この悩みの解決策探しのために、色々と読書した。
キリスト教が、ダーウィンの進化論を否定するのは、「仲間は最大の敵」だからではない。神、創造主の存在を進化論は否定するためだからと言う理由である。
そのため、キリスト教では、私の悩みに対する解決策は無かった。
また、宗教にも解決策は無かった。
経営の本には、喜び見たいのを感じた。しかし、いまいち解決策までには至らなかった。





では、「仲間は最大の敵」であるの解決策をここに述べよう。

経営の分野で「組織力」なる言葉があるが、それにはチームワークが無くてはならない。
これが、解決案である。

強いサッカーチーム、野球のチームには、チームワークがある。そして、必ず技というものがあり、それは連携プレーとも呼べる。
この連携プレーは、武道においては、「技」と呼ばれる。
将棋や囲碁においても、駒の連携プレーがある。
音楽において、ハーモニーも、連携プレーである。
リズムとテンポを合わせて、各楽器が、強すぎる音も弱すぎる音も早すぎる音も遅すぎる音も出さないで、調和させるのも技である。
技は、確実に実戦で出せるようにするために、何度も何度も練習して訓練するものである。

コンピューターにおいて、マルチタスクのシステム。並列処理のシステムも、DFDの設計図は、各タスクの連携プレーの技が書いてある。
という事で、システムには、組織力がありチームワークがあるのである。
システムは、仕事にも存在し、あらゆるゲームにも存在し、あらゆる趣味にも存在する。
そして、このシステムとは、「宇宙」とも呼べる。そんな世界観を持つ言葉だ。

ここまで理解できれば、サッカーは宇宙だ。野球は宇宙だ。スポーツは宇宙だ。武術は宇宙だ。音楽は宇宙だ。囲碁・将棋は宇宙だ。という言葉を納得する事ができるだろう。

この宇宙という私なりの言葉を理解できれば、この森羅万象の宇宙において、「仲間は最大の敵」であろうはずがない。
「仲間は最大の敵」である社会があるとしたら、それは、欠点というよりは、欠陥のあるシステムと呼べるだろう。
それは、正しい答えの元で修復されねばならないシステムなのだ。






宇宙は、組織力のあるシステムである。
ここで、一体感だとか、そういう話は、しない。
機械設計だと、マージンだとか、そういう話もあるが、そういう話はしない。しかし、それに近い話をしよう。
人間社会において、組織力の源泉とは、「信用」であろう。

この「信用」に関して、韓非子の話を元に、語ってみよう。

まずは、冠係と衣装係の話から始めよう。

王様は、ある日、酒に酔って床に寝転がっていた。
それを見た冠係は、王様が風邪でもひかないようにするために、衣装をかけてやった。
王様は、起きた。そして、自分に衣装がかけられているのに気づいて、
「私に衣装をかけたのは、誰か?」と問うたら、「冠係です。」という答えが返ってきた。
それを聞いた、王様は、冠係と衣装係を呼んで、二人とも罰した。
その理由。衣装係は、自分の役目の仕事の責任を果たさなかった。
冠係は、たとえ良い事でも、自分の役目以外の仕事をした。
これが、理由。

これは、人間の役目を機械の部品の設計のように設計して仕事を任せているのである。
機械の部品は、自分の役目以外の仕事はしない。
これが、かえって、組織力を作り出す源泉となる。
機械の部品は、人間力なる言葉では動かない。自分の役目に忠実であるかどうかが重要となるのである。
人間を人間だとは思わない。システムの部品であるというという思想で、仕事をさせたり、社会を機能させるのが、韓非子の基本である。

次に、また、韓非子から。

王様は、爪を切って、自分の手の中に切った爪を全て持っていたのに、こんな事を言いました。「自分の手の中に自分の切った爪の全てが無い。どこへ行ってしまったのだろう。嘆かわしい。」
すると、臣下の中に、こんな事を言う者が出る。「王様。落とした爪は、ここにあります。」
こう言う臣下は、世の中には、必ずいる者で、そう言う臣下は信用できないから、殺しなさい。
これが、韓非子の基本。
つまり、証拠固めした上で、わざと嘘を言って「試す」のである。

では、試すの例でも描いてみよう。

ある日。セールスマンがやってきて、雑談をする事となった。
そして、このセールスマンは、韓非子を知っていると言うのである。このセールスマンは、セールスのために気に入られるために、こんな事を言った。
お客さんは、試した。
冠係と衣装係の話をわざと変えて見てどう答えるかを見極めるためである。
 王様は、酒に酔って、裸で寝転がりました。
冠係がそこにやってきて、この王様に衣装をかけました。
起きた王様は、自分に衣装がかけられていたのを喜んで、誰がこの衣装をかけたかを聞きました。
そして、冠係がこの衣装をかけたと聞いたので、
王様は、冠係と衣装係を呼んで、「問題があれば皆んなで助け合う事が大事なんだ。」と言って、
冠係と衣装係を褒めました。
 これを聞いたセールスマンは、大きくうなずいて、「そう言う事が人間にとって大切なんだよ。」と言いました。
果たして、このセールスマンは、信用ができるかどうか?

ざっと、こんな話を作るあげる事ができるのである。

ただし、子供は、この上に、輪を描いて、こんな事をしでかす。
相手を試し、その上、信用できない根拠を答えとして話してしまうのである。
大人は、こんなバカな事をしてはならない。
試すとは、あまり、人に褒められる事では無いからだ。
子供のような喧嘩は、大人は、やらない。
ただし、相手の事が信用がおけるかどうかを判断するためには、致し方なくやるのが「試す」なのである。

以上の事を考えて、私は、「仲間は最大の敵である」と言う問題を解決していった。
そして、私は、社会に対してこのような望みを持っている。
経営者とは、「従業員に徳を積ませて儲けを得る」のが役割だと。
そうだとすると、誰もが、韓非子の支配の理論から成る社会よりも、ずっと素晴らしい社会を作る事ができるようになるだろう。



仲間は最大の敵である。それは自然状態。自然状態から平和を作る道とは、もしくはシステム化するための道とは、「秩序」を作る事である。世界秩序、社会秩序。
秩序とは、どこから作られるか?それは神の御心である。そして、それが、組織の理念となって組織のシステムに秩序を構成、構築してゆくのである。
理念とは、システムを構築している神の御心と言う精神を言葉にして表すものである。
ヨハネの福音書の最初。「初めに言葉ありき。」それは、神の精神であり御心であり理念であったのだ。
ただし、神の御心で作られたシステムも、神の御心を忘れて、社会秩序だけ取り残されたら、身分の序列だけで物事を判断する世界が誕生する。これは、まだまだ救いがある世界だが、世界の意味が失われて秩序だけ残った世界である。だから、原点が必要だ。その原点とは神の御心である。そして、それは理念なのである。
それは、世界に意味を与える言葉、秩序に意味を与える言葉なのである。初めに言葉ありきの世界の中では。

ここで、理念とは、神の御心を言葉にしたもの。システムの精神を言葉にしたもの。
秩序とは、従うべき行動の規範。例として、身分の序列を言い表す礼儀が言える。
トマスホッブズの王権神授説の王、孔子の君主は、神の御心を行う中心人物という事になるだろう。

通信プロトコルの基礎。双方向通信。ENQを使う。著者:吉田作太郎

全二重の通信回線ならば、通信制御コードにENQを使うのは良いだろう。
トランスペアレントな通信ならば、ENQを含めた通信制御コードに、データーリンクエスケープ・コード(DLEコード)を使えば良い。

主局と従属局があれば、主局側からの電文送信は、STX,ETXで囲まれた電文を遅れば良い。
従属局から主局への電文送信は、まず、従属局から、ENQコードを送ってみて、主局から、ACKコードのレスポンスが返ってから、STX,ETXで囲まれた電文を送るのである。

エラー・リトライ・シーケンスは、次の通り。

主局から従属局へ、STX,ETXで囲まれた正しい電文が来たら、従属局は、ACKのレスポンスを返す。
従属局からACKのレスポンスが来なく、タイムアウトになっても来なかったら、同じ電文を主局は伝送する。
このタイムアウトが、三回ぐらい来たら、主局は、従属局と接続不能状態となったとみなす。
接続不能状態になったら、接続不能状態であることを示したアラーム点灯と音を鳴らしながら、従属局との再接続のための、通信プロトコルシーケンスを行う事。
再接続のための通信プロトコルシーケンスの作るコツとは、従属局が電源を入れ直して正常受信可能状態にさせる通信プロトコルシーケンスを考案する事。(NTT用語では、この通信プロトコルシーケンスを担当するタスクの処理の事を再開処理と呼ぶ。これは、すなわち、通信のための初期処理の事である。)

従属局から主局への電文がある時は、従属局から主局へENQコードを送信し、ACKのレスポンスを待つのだが、主局側からSTXの電文が来たら、STXの電文を優先して受け入れてその電文が正常電文ならばACKのレスポンスを主局に返す事。
そうでなく、ENQコードを送信した従属局が、主局のACKコードをなかなか受信できなくなっている場合、タイムアウト時間まで待って、まだACKコードを受信できない場合、また、ENQコードを送信する事。このタイムアウトシーケンスが三回以上続くのであれば、従属局は、接続不能状態である事を示すアラーム点灯と音を鳴らしながら、タイムアウトシーケンスを伴いながら主局へ送るENQコードを送り続ける事。

その他にも、色々とトラブルについての解決策が必要となるかもしれないが、正常シーケンス以外のエラー処理は、ほとんどの場合「無視」が一番の解決策である事をここに述べる。

これらの処理を作り、正常に機能するようになったら、主局と従属局間の「接続チェック処理」を入れる事。
これは、ポーリング処理を改良したものが参考となるだろう。
または、ヘルスチェックというのも、参考となるだろう。(ヘルスチェックは、NTTの企業用語である。IT用語、ヘルスチェックをキーワードにンターネットで調べれば分かる。)
接続チェック処理は、プログラム開発の初めから考慮して作ってはならない。
初めから考慮して作って入れておくと、デバッグが大変になってしまう。
通信プロトコル作成の最後に、デバッグまで済んで正常だと判断した時に、接続チェック処理を付加させる事。

以上。

無限について考える。 著者:吉田作太郎。


ツェノンのパラドックスなんかで有名な無限。
昔、博識な誰かさんが、無限と宗教をイッショクタンにしていたようだけど、最近、少し、分かるようになった。

無限とはアンカウンタブルという意味を大学で知ったが、それが何かまでは、認識できなかったが、最近の認識では、無限とは、通常状態と比べて、突然性質が変わる極限状態の事を無限と呼ぶらしい。
であるから、きっと、無限とは、値が不定状態ではなく無定義状態の特異点という事になるだろうか。だから、その部分だけさけて、無限を取扱う時は、「近傍」なる言葉を使わないと取扱えないというしろものである。

無限とは、別に、「無限大」とは違うのである。
無限とは、単なる特異点だ。
無限大が、特に、特異点であるという事から無限なのだろう。
最大の数値の特異点の事を無限大と呼び、我々が知る事ができるのは、その近傍しか分からないのだ。また、無限を取り扱う場合、どっち方向からの近傍かというベクトルまで必要とする。

無限になったらどうなるか?答え。無定義。
無限を超えたらどうなるか?答え。無定義。
これが、人間が知る範囲というものである。

生きるという特異点とは、生まれる事と死ぬ事である。
そこで、宗教とは、この特異点とそれを超えたらどうなるかを話し合っている。
実にくだらない事である。
人間の知識では、それは、無定義な部分でしかない。
そこで、宗教とは、ヴァーチャルな存在を用意した。

神。魂。霊魂。

未定義なものを論議するのは、愚かである。
また、その時は、現実からの呪縛が一切断たれた空間なので、異次元の話になってくるのはしかたがない事。

宗教とは人間の知識の範囲外な事でしかない。
それは、「無限」なのであるから。

さて、ツェノンのパラドックスで、特異点とは何か?
これは、単なる言葉の呪いでしかない。

アキレスは、亀に追いつくまで、追いつけない。
これが、限界だ。この限界とは何か?
アキレスが亀に追いつけないがそれでも追い越そうとした場合の特異点とは何か?
そういう言葉の呪いの中に、無限が有る。この無限とは、アキレスが亀に追いついた時と、追いついた後が、つまり無限であり特異点である。

そう思っておけば良い。

それは、まるで、人間が死ぬ時は、どうなるか?
人間の死後の世界はどうなっているか?
そんな討議をまるでしているかのような話が、ツェノンのパラドックスなのだ。
これは、案外、宗教的な皮肉みたいなものであろう。

アキレスが亀に追いつく瞬間があるのに、また、追い抜いてしまった後の時間があるのに、
なぜ、人間には、死の瞬間や、死後との世界が無いなどと言えるのだろうか?
それは、単なる人間の認識の世界の中では無定義状態である。
単なる特異点でしかないのである。
認識の特異点が存在して無定義ではあるが、実際、シミュレーションしてみたら存在するではないか。
つまり、人間が、神や魂の存在を認めて、死の特異点という認識から逃れたら、そこには、魂や霊魂なる世界が存在して、死の認識を更に確実に理解する事ができるはずだ。認識する事ができるはずだという、あがきにもにた、詭弁の言論が、ツェノンのパラドックスという訳だろう。

さて、現実の問題について考えてみよう。
無限分割は可能か?
数学上は可能であろう。では、リアルではどうだろうか?
リアルな世界では、無限分割は不可能である。
量子力学的な小ささまで分割したら、もはや、今までの物理法則が成り立たない状態になってしまう。
また、無限大は存在するだろうか?
リアルな世界で、もし、無限大の空間を空想したとしたら、その果てはもは今までの物理法則が成り立たない状態になってしまう。
これが、特異点というものである。
そして、現実とは、この特異点になるまでは、通常の法則が成り立っている。
ただし、特異点になってしまったり、特異点を超えてしまったら、通常の法則が成り立たない事態が発生する。
そんな示唆を与えてくれる言葉が、「無限」というものなのである。

無限というものを、ウロボロスの輪によって表現する。「∞」
もし、この世が、デジタル回路のカウンターの様なものだと達観したとしたら、この無限という言葉を「∞」と表現するのは、一種の皮肉みたいなものだろう。
輪廻転生なる話も、宇宙の法則に従って生きていれば、結局は、宇宙の輪から逃れられない運命であり、輪廻は繰り返すものであるという認識になってしまう。
そして、我々が、神や仏を拝む時、両手を合わせる行為とは、六道の天界と地獄界をつなぎ合わせる行為にも似ている。
もし、この時、地獄にいるのであれば、手を合わせて拝む行為とは、きっと天界へと通じる行為であろう。
しかし、天界にいるのであれば、手を合わせて拝む行為とは、地獄行きもあるかもという行為であろう。

我々が、神に対して拝む行為とは、常に上を目指して、天上界にいようとも、常に地獄に堕ちる事を厭わないで、前向きに前進する姿でありたい。
これが、宗教的呪いに対する特異点への祈りとなるものなのであろう。

著者:吉田作太郎。

並列処理概論 ver2.(3/3)著者 吉田作太郎

12.チケットプリンターを作った時の例。

 昔、航空機のチケットを発券する装置、ATBチケットプリンターの開発をした事がある。
マルチタスクOSを用いないでアセンブラで開発した。
つまり、シングルタスクである。
さて、このチケット。チケットを発行依頼する機械からの命令でチケットを発行するのだが、チケットプリンターで2枚同時にチケットを搬送できる様にする事が一番の目的であった。
普通、シングルタスクでは、チケットを一枚ずつ発券するしかない。
これを可能にしたのが、シングルタスクに大きなループを作って各タスクにタスクスイッチを配備して作るマルチタスクシステムであった。
我々が手がけたのは、搬送系という部分であった。
チケットを搬送するタスクを3つに分けて作った。
また、チケットを搬送させるためのパルスモーターの設計もした。
 さて、チケットを搬送するタスクは、光センサーによってチケットの動きを監視している。
その部分は、チケットを搬送するとき光センサーがどのようなオン・オフの動きをするかというタイムチャートが渡され、そのセンサーの動きに従ってタスクを動かすという設計であった。
ここに一人のできの悪い年配者のプログラマーがいて、この者が作ったタスクのフロチャートはごちゃごちゃしていた。矢印があっちへ行ったりこっちへ行ったりして、意味不明のフロチャートを提出してくるのだ。
普通、チケットという紙が動いたら順番に動くものであるから、書くフロチャートも紙が動いた順番に条件ジャンプするというえらく簡単なプログラムのはずなのだが、この人が作るプログラムは、そんな事はえらく無視したものであり、作り直しという修正依頼しても拒絶し、しかも、こちらからの仕事の作法を全く学ぼうとしないという困った人間だった。
私は、この男が私の耳元で今にも殺されそうな声でがなりたてられたので、その夜、中耳炎になってしまい、仕事に参加する事ができなくなってしまった。
さて、結合テストになった。
中耳炎で苦しんでいる自分に電話がかかってきて、仕事に参加してくれという事であった。
行ってみると、皆、困っている顔をしていた。
私だって、誰が作ったプログラムの内容なんか全く分からないのだが、デバッグした。
するとどうだろう。
後から後から、バグだらけのプログラムを渡されるのであった。
私が以前いた時は、威張っていたり、こちらの事をばかにしたり、今にも殺されそうな声を出して中耳炎にさせたりする人間が、とても不安そうな顔をするのであった。
こう、客にべったりついていると、この人間は、顧客を恐れているらしい。
これらのプログラムのバグは、全てこの人間がしでかした事であった。
私がこの仕事を担当すると、私とこの私を中耳炎にさせた人間と一緒に仕事をする事になってしまっていた。結局、皆、自信が無くてこそこそと逃げ出した訳である。
さて、一通り仕事を終えて帰ろうとした時、タスクの間違い箇所を見つけた。
それは、チケットを搬送するタスクは光センサーによるタイムチャート図通りに作っているのだが、モーターを停止するための部分は、モーターが停止するまでタスクの全体のループにもどさずそこの部分だけ無限ループ(ビジーループ)なのである。
これを修正しようと私が意見を言ったら、この私を中耳炎にさせた人間はとたんに拒絶した。「黙っていろ!!黙っていなければ俺はおまえを絶対許さない!!会社で嫌がらせしてやる!!おまえの言う事は絶対聞かない!!」
はてさて、どうしたものか。
 普通、正しい善悪の判断とは、修正せねばならないのは当然である。
しかし、この会社の社会では年齢に対する敬意を示さなければならない。これも、善悪の判断基準である。
この人間はいったい何を考えているのだろうか?
私は、疑問に思った。そして、私は、この人間を説得しようとしても、一向に言う事を聞かない。この人間がそこまでして何かを守ろうとする意思とは何かを疑問に思いながら、私は修正する事を断念した。
 さて、その夜、仕事を終えて、この人間と一緒に旅館で宴会を開いた。
そして、たずねた。
「お客さんから、自分の仕事に関して問題がある時、客から修正依頼を依頼されたらどうしたら良いでしょうか?」
その答えとは、「工数がかかります。と言っておくんだよ。」という事だった。
「我々の仕事とは、”受託”であり、”善管注意義務”なんだ。だから、責任というのは全く無いんだ。相手の方から仕事を依頼されたら、工数がかかりますと言っておく事。これでたいていの仕事に関する依頼は断る事ができる。これプログラマーとしてのビジネスとしての常識。」と言われた。
しかし、私が呼び出された時は、このプログラマーは、たいそう困った顔をして、悩んでいるようであったが、これは、やっぱり、怒られるのが怖いらしい。
ただし、私の前では何も怖くは無いらしい。
この人間、これ以降、自分の我ばかり通して、一生懸命に私に教えると称して仕事以外の昔のレザークラフトの仕事だとか競馬だとか競輪などの話を一生懸命に私に教えようとした。
いったい、この人間は、会社に何しに来ているのだろうか。
こちらから、教えねばならない事が沢山あるというのに、一向に学ぼうとしてくれない。
ところで、この出張から帰った時、この仕事ができなくて逃げ出した上司を含めた人間達に、事の一切を説明した。普段ならば、「あれはいけない。これはいけない。」なる説教をするはずの上司や先輩達は黙ったままであった。
この当時は、なぜ、その様に黙っていたのかは理解していなかったが、私は、どうやら、悪党達の集まっている会社で仕事をしていたという事だったらしい。
メチャクチャだとかいい加減すぎる職場という事は、悪党だと罵られてもしょうがないだろう。
 さて、この件で思った事は、アセンブラでのシングルタスクのマルチタスク化とは、ちょっと修正するのに、大変手間暇がかかる。
このパルスモーターの停止部分をもしマルチタスクのシステムコールを使うとしたら、間違いなくのRUN状態をREADY状態にさせるためのμITRON_OSで使われているローテーション・レディーキュー(rot_rdq)処理を付け加えたい所だが、もし、ここに、プライオリティーの問題が発生したとしたら、タイマーウエイトを使って問題解決する事だろう。これが、一番の応急処置となる。
今は、そう思っていて、ビバ、マルチタスク!!だが、やっぱり、ヘンテコリンナ人間と一緒に仕事をしていられないものだ
それは、相手も同様であろう。
だって、自分勝手に動かないプログラムを書き続けて、労働したと思い込んで、それを実践に提出しようと無理するのだから、互いに嫌な思いをする。
更に、自分が間違っていても、強情を働けば通ると思い込んだら付け上がる人間である。
だって、不誠実な事でも、権力を持てば自分の自由になると思い上がっている人間であるからだ。
であるから、そういう事が無いためにも、正しいか正しくないかという考え方とは別次元で権力なるものが無ければ、人は思うとおりに動かないし、善の方向へ動こうとしない人間も多い事を心得ておいた方が良いだろう。
世の中、いろんな意見があるから、人の話をよく聞いて判断すべきだという意見があるだろうが、仕事をする上でどうしても妥協できない事柄ってあるものだ。
であるから、自分が正しい行いをするためには、権力を持たねば、不誠実な人間達からバカにされて、正しくあるべき仕事をないがしろにしてしまう事もある事を心得て、男というものは権力闘争する必用があるのだ。
それは、「ならぬものはならぬのです。」という精神を貫くために。
世の中とは、正しい事を実行しようとする場合、権力は必用である。
悪いと分かっていて同じ仲間として悪い事をする馴れ合いや、丸め込みなる事。こういう時は、仲間意識というのが邪魔であり、仲間である事よりもリーダーやマネージャーである事を自覚して、正しい事正しくない事に関して自分と意見が合わない事柄は公の立場としての正義を貫くために、仲間である事よりも支配者である事を自覚して威勢を使って、それは簡単に言って威張って威圧する事なのだが、そうやって人を使ってゆかねばならない。
特にコンピューターの仕事とは、自分達の仲間の他に、他人様の人の命や大きな財産に関わる重要な仕事である。
リーダーやマネージャーはそれを心得ておいて権力を使い威勢を使わなければならない。
それは、つまり権力や威勢は、ふざけて遊ぶ、遊び道具や、自己弁護のために使う道具ではない事を心得て、自分が公の人間であるという使命と責任感を貫くために使う事。
後、リーダーやマネージャーは、子供の様な「ふざける」なる事をしてはならない。
ユーモアと「ふざける」を混同しない
それは、リーダーやマネージャーの役目は、管理監督業であるから、何かが問題がある前に悪の兆しを断つ事も仕事の内である。
ふざける事とは、「親しみやすさ」、「フレンドリーな事」と周りの者達が称している事だろうが、実は仲間の中に入り込んでいる己の正体を明かしていない隠れた悪人からの馴れ合いや丸め込みを受け入れやすくなるという悪の兆しを受け入れやすくなる事であるので、そういう悪の兆しは断った方が良い。
 次に、ビジネスとしての話だが、この業界の下請け会社のほとんどは請負契約ではなく、準委任契約である。請負は不出来な仕事には金を払わず返品しても良いが準委任契約は「善管注意義務」という相手の善意だけを信じて仕事をまかせる仕事であり不出来な仕事でも金は支払わなければならない。
であるから、親会社が子会社に仕事の管理監督をして子会社が不出来な仕事をした場合、いいや、準委任や請負契約は、親会社が管理監督しても指示命令をしてはいけないという事になってくるから、どうしても指示命令がしたい場合、親会社は余分な工数の料金を支払って指示命令しなければならない。
ただし、相手ができの悪い技術者で、不出来な仕事しかできず、修正依頼して仕事をやらせても必ず仕事が失敗するなだとかいろんな問題がある場合、子会社側の人間が「工数がかかりますよ」と言った時点で、親会社の人間がその場で契約破棄した上に出入り禁止にして、二度とその会社とそこの人材に関わり合わないようにするものであろう。
ただし、相手が有能な技術者であり、どうしてもやってもらいたい仕事がある場合、準委任契約の場合、親会社は余分な工数を支払って仕事を依頼する。
この時、親会社の人間は、「1日分の工数を支払うがやってもらえますか。」と言ってくる。
この時、ビジネス上、これを拒絶したら、この会社から二度と仕事がやってこなくなる。
であるから、「どのような内容の依頼でしょうか?可能な話ならばやります。」と言って、親会社の人間と相談して、知恵を出し合うコミュニケーションをし、不可能な仕事ならば、断るし、可能な仕事ならば受け付ける様にしておく事。
親会社から「工数を支払うからやってもらいた仕事がある」と言ってきた場合、それは、下請けであるあなたが親会社から信頼されての依頼である事がほとんどである。ほとんどの仕事は不可能な仕事では無く可能な仕事、場合により簡単な修正によって成し得る仕事が多いので、この依頼は、良いコミュニケーションをしてできるだけ仕事を受け付けた方が良いのである。
コミュニケーションは大事である。親会社から与えられる仕事で、不可能な仕事を与えられる時がたまにあるが、私の経験では、これは、試すためにやっている。特にこびへつらう人間を排除するためにわざと不可能な仕事を与えてみて、試す。この場合、拒絶する事が大事だが、きちっと、論理的な説明をして、断る事。もし、断らなければ、「こいつは、与えられた仕事に関してできるかできないかを判断する能力も無く、ただこびへつらっている人間であり、そういう人間の本質とは嘘つきであるから、後々ためにならないし、また、同業者としてそして仲間として「最大の裏切り者になる可能性の高い危険人物」である。」と認識されて、できない仕事を与え続ける事によって、仕事にわざと失敗させて、取引関係から手を切ろうとする事になる。
であるから、お客様からの仕事の依頼に関して大事なのは、自分勝手な判断ではない。
きちっと、仕事の内容を吟味してみるコミュニケーションをしてから、お客様良し、自分良し、公のモラル良しという「三方良し」の哲学を元に、仕事を引き受けたり断ったりする事が大事なのである。




13.労働について考える。

 あらゆる労働とは、並列処理である。であるから、業務フローを書いて順番に実行されるべきものである。
また、この業務フローが完成していれば、他の人を雇って並列的に仕事をさせて、人数を投入させた分、仕事を効率的にこなしてゆくのに役立つ。
すると、仕事の管理監督する側も、この業務フロー通りに仕事をこなしているかどうかによって、仕事の成果を計測しながら数値化して計測する事ができる様になるのである。
 さて、企業の品質管理にISO9001なるものがある。
どうやって、品質管理すれば良いか?
職人芸では、成果物でしか管理できない。工場のように各担当を決めてプロセス通りに製品を作っている部門では、決められたプロセスを作り、人を使うのに決められたプロセス通りに人材を配置し作業をさせれば管理できる。
まるで機械設計の概念で人を使い管理する。
この様に、仕事を管理監督する側とは、人や設備を使うのに決められたプロセス通りに事が進行しているかどうかを管理すれば良い。
このプロセスの管理の基本とは何か?それは、業務フローを作って管理する事である。
次に仕事に使われている用語の定義をしっかりして仕事の担当者と管理監督者が共有している事。
その他に、仕事の作法を文書化して、仕事の担当者と管理監督者が共有している事も大事で有る。
このアウトラインができて、やっと、仕事というものをシステム化する事ができ、そのシステムを管理監督する基礎を作る事ができる。
 しかし、この管理監督には、欠点がある。
確かに、この様なシステム化をして管理監督をすれば、余裕を持って人々が担当した作業をしてくれて、一定の品質を保って作業をする事ができるが、それは同時に機械的なマルチタスクOSが成し遂げる品質管理と資材管理と財務管理と時間管理しかできない。
この作業のやり方とは、大企業がやる仕事のやり方である。
これに比べて、職人と呼ばれる人間の仕事のやり方とは、まず作業の業務フローは全て自分に身に付いている。そして、全ての作業は、マルチタスクOSのスケジューリングではなくて、その職業専用の優秀な知能付きで全ての業務フローをマルチタスクOS以上のマネジメント能力によって短時間で高品質な製品を作ってゆく。
その代表的な職人の例とは、レストランのコックがあげられる。
コックは、複数の注文を受け付けて全ての料理を作る業務フォローをマルチタスクOS以上の知能付きスケジューリングでこなしてゆく。
こういう記述をすると、大企業よりも熟練工がいる中小企業がすばらしいという感じであろうが、実際は違っている。
マネジメント能力に関する無知な中小企業の経営者や上司がいて、「仕事とは盗んで覚えるもものだ。」という教育を与えて仕事をさせて、従業員に無理な経営や業務の管理監督をする事があった場合、従業員に無理な仕事をさせて大失敗してしまうケースが多い。
また、せっかく作ったISO9001があっても、管理監督者が怠慢であったり、従業員が不真面目であって守る気が無かったりすれば、仕事というものは大失敗してしまうものである。
 会社が小規模な経営から大規模な経営へ変わる時、もし、品質管理のISO9001のようなものがあるとしたら、韓非子に書かれている様な管理監督が必用である。
「王様が、酔いつぶれて床の上で寝てしまいました。それを見た冠係が、王様を気遣い王様に衣をかけました。王様は、起きると衣をかけられた事を喜びました。そして、王様が、誰がこの衣をかけたのかと聞いたら、冠係がかけたと聞いたので、冠係と衣装係を呼んで事実を確かめた所、本来、王様に衣をかける仕事は衣装係なのに冠係がかけたという事で、王様は衣装係と冠係の二人を罰しました。」
ここで言う所の王様とは、管理監督者の事である。
規模が大きな経営となってくると、仕事とはシステム化して機械の様に動かす事。
そして、仕事とはプロセスを大事にする事。
そして、そのプロセスを担当する人間は、他の仕事と兼任してはならない。また、他の責任者になってはならない。
もし、他の仕事をしたり、他の仕事の責任者になったりしたら、罰する事。
そうやって、システムを動かす事。
すると、もし、成果物に異常があったとしたら、プロセスを確かめて、何がいけなかったのかという犯人や原因を見つけ出す事が容易になる。
更に、事前に異常事態が起こらなくさせる様にする事が管理監督者の指導によってする事ができる。
これが、管理監督という業務の基礎である。
マルチタスクを用いたアプリケーションの設計とは、システムの設計であり、この様に労働の管理監督業の知識と関連し合っているのである。
 私がプログラマーの時、やたら部下が「吉田さん。人を使うのは難しいよ。」なる事を言っていた人間がいた。私は自分なりの意見を言ったら「そんなんじゃダメだ。人間は機械ではないのだから。俺が人を使う事ができるのは俺には感受性があるから人を使う事ができるのだ。」なる事を言っていた。
ある日、お客さんとその部下と一緒に会議に出たら、その部下は、やたら、お客さんに体全体をゆさぶり動かしながらペコペコしてご無理ごもっともと言ってきた。私が、仕事の会議に口を出そうものならば、怒り出す。その理由とは、「なぜ拒絶するか?」という怒りの感情でこちらを威圧するのであった。
自社に戻って今度は部長と一緒に会議をした。そして、私は部長の前で、この部下が勝手に約束できない仕事を取ってきたとクレームを言ったら、今度は、この部下と部長は、私を悪人にして「仕事を拒絶してはいけない。」と言い張り、そして部長に仕事の進捗予定表を書けと言われた。その書いた予定表は納期に間に合わないものであった。そしたら部長は怒って「それじゃダメだ。納期まで間に合うという予定表を書け。」と何度も言われ、そしてとてもじゃできないという予定表を書く結果となった。
この部下、今度は自分の関わっている仕事について私にあれこれ聞いてくる。これは仕事を教わりたくて聞くのではなく、また、問題点の原因を探ろうともせず、また、何か問題点が明確になってそれを聞いてくるのではなく、こちらをやり込める感覚で聞いてくる。この質問の中で通信電文の優先順位順に制御する部分が出てきてそれについて考えたら、優先順位順を制御する部分に問題点がある事を見つけた。そこで、私は親会社にこの問題点を報告してもっと簡単な制御を提案したのだった。するとお客さんの方で、いそがしいだろうから、与えた仕様をもっと楽にしてやろうという事になった。ただ、この後でも、この部下は、お客さんからの仕事を沢山取ってくるのであった。
はたして、この部下の言う「人を使うのは難しいよ。」なる言葉。
これ、「人を管理監督して仕事をスケジュール通りやり遂げる方法論。」なる基本法則を無視して、仕事に関して口を出し、スケジュール通りにいかない仕事でも簡単に取ってくるからたまったものではなかった。
この部下の言う「人を使うのは難しいよ。」という言葉。
これは、いったい何だったのだろう。結局、彼には、彼独特の人付き合いだとか親睦だとか人への気遣いだとか、それに基づくコミュニケーションが大事だとでも言いたいのだろう。そして、お客様にべったりと張り付いて一生懸命に、お客様のために、コミュニケーションしようと頑張っていたのだろう。そして、こういう態度が、客にとって、うっとうしいだとか、こびへつらっていて、いつでも約束できない事でも平気で約束する事ができる嘘吐き人間とでも思われたのであろう。こういう部下の様な人間がいて一緒に仕事をすると、デスマーチは必ず起こる。これでは、「人を使うのは難しいよ。」程度の騒ぎではない災難が訪れてしまうというものである。
 また別の話をする。有力なお客様からやってくる新規の仕事とは、会社内の優秀な人材を集めて仕事をするものである。そして、そのお客様から仕事が次から次とやってくると、今度は人材のレベルを下げて、優秀な人材は、また、新規の難しい仕事を担当させられるものである。
この人材のレベルを下げられた部署に配属されるとたまったものではない。
以前、優秀な人達と一緒に仕事をしていた人材がリーダーとなっているのだが、一般のプログラマーが入ってくると「レベルが低い」と怒り出す。そして、「もっと、レベルの高い人材が欲しい。」と言ってくる。
実は、コンピューターの仕事とは、インタビュー技術が必用だ。
それは、お客様の仕事の用語、作法、独自技術などを聞き出さなければならない。
また、最先端の仕事をやっている所の仕事の作法などは、そのほとんどが独自技術というものである。
そういう独自技術の用語や作法を教えられないで、一般のプログラマーを使っても役に立つはずがない。
以前からあるプロジェクトとは、二次三次の仕事がやって来て次々と人材が代わって人材のたらい回しにしている様なプロジェクトには、教育だとか、技術の伝承が必用なのだ。
それが分からないチームリーダーが仕事を仕切るとプロジェクトは壊滅状態になってしまうものである。
これは、また、その会社の上司も悪いし、人事も悪いから、この様な壊滅状態が生じるのである。
 さて、ここで、労働につて考える。
一番の基本とは、仕事には、用語の統一、作法の統一が必用であり、それに基づく知の伝承が必用である。
その知の伝承において、業務フローが書けるものがあれば、労働がパターン化する事ができて、楽である。
また、労働がパターン化する事ができれば、マネジメント業や管理監督業が楽である。
労働において、マネジメント業や管理監督業が規格化できている職場とは、労働者に無理な労働をさせないで、プロセス重視の仕事をしておけば、ある程度の品質管理ができて良い成果物を作り出したりサービスを顧客に与えたりする事ができる。
壊滅的な職場とは、用語の統一ができていない、作法の統一ができていない、それに基づく知の伝承ができていない。そして、リーダーが言う言葉は、「仕事は盗んで覚えるものだ。」とだけ言ってマネジメントしていると言っている職場である。こういう職場で働くと、よく聞く言葉は、「お客さんに虐げられてきた。虐げられてきた。」というリーダーや営業や会社の上司の愚痴である。お客さんの方も、プロジェクトのリーダーとのコミュニケーションにおいて、使う用語が一致していない、仕事の作法が一致していないのであれば、そういう人達と一緒に仕事をしても仕事に関して互いに理解し合えないから使い物にならない人達と思い、そういう人達が集まっているプロジェクトを排除したがるものであろう。

では、今度は、営業業務と管理監督業の事でも書いてみよう。
親会社が、子会社に電話営業を任せるのは、ただ、まかせてもしょうがないのである。
本当に真面目に、業務をやっているか?
言葉づかいは正しいか?
お客様に無礼なセールストークをしていないか?
正しい商品説明、サービス説明ができていないか?
このぐらいの事を親会社は、管理監督した方が良いだろう。
もし、この子会社に電話営業を任せている業務契約が準委任だとしても、外部監査みたいな形で管理監督したい所だ。
もし、管理監督しないとしたらならば、この子会社の電話営業を通して、親会社のイメージを悪くする恐れがあるのだ。
そこで、親会社は、子会社が勝手に電話営業をするのではなく、電話をかける先の電話番号のリストを用意しておいて、電話営業を担当するそれぞれの従業員にそれぞれ対応するリストを渡しておき、そしてそのリスト通りに電話営業をさせる。
その電話リストの中には、電話営業をきちっとやっているかを監視する人の電話番号を入れておく。
もし、電話営業の担当者が、さぼっていたとしたら、電話営業を監視する人に電話をかけてこないだろうから、そういう意味で監督業をする事ができる。
また、電話営業を監視する人に電話営業の人間が電話をかけてきたら、お客さんのふりをして正しい営業をしているかをチェックする。
電話営業をする人間は、親会社から渡されたリスト通りに電話する事。
たとえ友人から話を持ちかけられ、契約したい人間がいるとしても、無視して、そのリスト通りに電話営業する事。電話をかけるのはリストよりも多すぎても少なすぎてもダメだ。
もし、多すぎる場合、電話営業する子会社が、利益を得ようとしてやる事だろうが、こんな事をさせれば、親会社の監視の下で、この子会社は労働者に無理な仕事をさせていると判断して罰する事。次に少なすぎる場合、これは、さぼっていると考えて罰する事。
そうすれば、働いている人間達に労働法を守らせて、定時入社、定時退社させて、労働力を疲弊させる事無く、管理監督して労働をさせる事ができる。
ここで、営業ノルマの問題があるだろうが、そんな金よりも、敬語を使い正しい商品説明をしてくれる人間が電話営業をしてくれるのならば、会社のイメージやブランドを良いものとして維持する事ができる。
契約したり売買したりして金を得る事だけが営業では無い。
イメージ戦略、ブランドイメージを良くする事も含めて営業なのだ。
こういう管理監督方法があるとしたら、今度は、テレビの宣伝などで電話を受け付ける営業も同じ手が使える。
電話営業の管理監督者が、この営業へ電話をかけてみる。
なかなか電話に出なかったりしたら、この会社の本部へ電話をかけてこのお客様から電話を受け付ける電話営業はどうなっているかと問い合わせてみる。
そしたら、さぼっているか、さぼっていないかを確かめる事ができる。
また、電話が通じたら、電話営業に商品の説明をさせてみる。
敬語が使えなかったり、しどろもどろの営業だったり、ろくな商品説明ができなかったり、間違った商品説明しかできなかったりしているかを判断する事ができるだろう。
こういう時、嘘を言って確かめる事もする。
これで、いい加減な返答をする人間がいるかという事も確かめる事ができる。
こういうのも、管理監督業の仕事である。
 次に、自動車販売会社での管理監督業について考えてみよう。
電話での応対でも、ある程度分かる。
その他に、自動車販売会社とは、自動車を売るだけではなく、車検や定期点検のサービスを受け付ける事も業務の一つだ。
車検や定期点検のサービスのやり方を、営業本社からのコンピューターを使って、葉書だけ出してそれで満足している営業って怠慢だ。
それは、営業幹部は無能者ぞろいだという事でもある。
自動車販売会社では、サービス期間を設けてそこでお祭りをして、プレゼントを配ったりするものだ。
これと、車検と定期点検のサービスを結びつけようとする営業がいないものである。
営業販売所には、きっと顧客情報管理のコンピューターがあるはずだ。
車検や定期点検の期間と、自社の営業のお祭りとを関連付けて、お祭りの時、見込み客がいれば、積極的に、「お祭りがあるから来てください」なるラブコールを営業マンにさせ、そして、来てくれたお客さんに景品のサービスをしたりして、一言「車検の件よろしくお願い申し上げます。」なる事でも言っておけば、また、そこは、営業というサービスマンなのだから、いろいろとセールストークを研究しているのだから、その研究成果を出して、印象を良くして、お客様が車検してくれるようにするのも営業の仕事である。
そうすれば、お客様と営業マンとの接点が多くなり、車を買ってくれる見込みのあるお客様を多く獲得する可能性を高くしたりする事だってできるだろう。
これらが、営業の管理監督業によって成される効果というものである。

 次に、今度は、ブラック企業の考察をしてみよう。
品質管理基準であるISO9001があったとしても、人材派遣会社に仕事を依頼する場合、品質管理する業務を怠りながら労働者に仕事をさせている事があるものだ。
最初、人材派遣会社から人材を雇う時、労働法で規定された派遣契約で仕事をしてもらう事となるだろう。
この時、親会社は、派遣社員を管理監督して仕事をする事となる。
という事で、親会社がしっかり仕事の管理監督をすれば、ISO9001を守って仕事をする事ができるので、親会社良し。労働者良し。労働法良しの三方良しの仕事をする事ができる。
ここで、人材派遣会社の営業が、親会社と交渉して、今の人材に与えられている仕事を準委任契約にしませんかと話を持ち込む。
もし、この準委任契約が成立すると、この人材派遣会社は、派遣契約よりも親会社に対して高い金額を請求する事ができる。
この時、ここの労働者に対する指揮命令権は、親会社から人材派遣会社へ移る。
また、この労働によってできあがる成果物の責任は人材派遣会社はとらなくても良い。ただし親会社は、この人材派遣会社に対して、善管注意義務という善意だけを信じる事となる。
準委任契約で、人材派遣会社が、ISO9001に基づいて労働者管理してくれれば万々歳だが、これがなかなかうまくゆかない。
その理由。この人材派遣会社が生産して作る成果物に対して、人材派遣会社は実質上責任を取らなくて良い。請負契約ならば責任を持たねばならないが、準委任業務ならば責任は全く無い。人事派遣会社が「善管注意義務」やってますと言い張れば、責任を取らなくて良いのだ。これでは、ISO9001という品質管理ガイダンスを別に守る必要も無いし、また、本来、ISO9001に基づく管理監督業の担当者の存在が明記されていたとしても、そんなの労働者にまかせていて、「この労働者が兼任で管理監督業をやっています。」と言い張り、善管注意義務を盾に取れば、それを認めなくてはならない。
そもそも、管理監督業としての命令指揮権は、親会社に無く、人材派遣会社にあるのだから、親会社が、ISO9001を盾に取ってクレームを言っても、そこに法的罰則が無い状態である。これでは、人材派遣会社だけが金儲けができ、親会社損、労働者損、その商品を受け取るお客様損、世間が損の四方損の状態が生まれる事となる。
この様に、いくらISO9001という品質管理基準があったとしても、それが守れない日本の社会の仕組みというのが有ったりする。
この準委任契約による四方損を生み出す会社は、現在、ブラック企業として、この日本に存在している。
 では、ここで、人材派遣会社が行う契約、派遣と準委任契約の内容を比較する。
派遣  命令指揮権(派遣先)
 対価支払い(時間)
 完成責任(なし)
 適用される法(労働法)
準委任 命令指揮権(受託者)
 対価支払い(時間)
 完成責任(なし)
 適用される法(民法)
請負  命令指揮権(受託者)
 対価支払い(一括)
 完成責任(あり)
 適用される法(民法)
 では、私が派遣会社側の人間ならば、自分に有利になる展開でも考えてみるだろう。
まず、親会社と契約して「準委任」の契約を取ってくる。
次に、労働者は、人材派遣会社の人材としての労働者ではなく、まず、労働法の適用を受けている労働者の身分を剥奪して民法の適応を受ける個人経営者とする。
そして、人材派遣会社は、親会社と労働者との間に立って、「民法適用の準委任の経営者同士の契約を担う手配師」となろうとするだろう。
そして、労働に関しての命令指揮権は、人材派遣会社が持つのではなく、労働者を受託者とさせ労働者自身が与えられた業務を命令指揮する者とする事だろう。
そして、労働者自身が、ISO9001を守ってもらえれば良い。ISO9001を守るのは、親会社でも、人材派遣会社でも無く、今は労働者の立場を剥奪されている元労働者である受託者である。
利益を求める人材派遣会社は、ざっと、こんな事を考えて、親会社と人材派遣会社から仕事を求めてやって来る人材の立場を取り持つ事であろう。
人材派遣会社の言葉は次の様なものとなるだろう。「労働者なる言葉は古い、古い。今は、個人経営者の時代だ。我々は、会社と個人経営者の間を取り持つ人材派遣会社である。」
はてさて、これでは、ISO9001という親会社の求める品質管理が守れるか?
ISO9001が守れなかったら、その責任は、人材派遣会社が全く持たず、元労働者の立場の成れの果ての個人経営者が持つものであるのだろうか?
ただし、この民法の準委任契約の個人経営者は、製品の完成責任を任せられている請負契約の業者では無く、製品の完成責任を持たない善管注意義務だけ守っていれば良い個人経営者である。
誰も、ISO9001は、守らないでしょう。
この様に、日本の中小企業の産業能力は衰退の一途をたどる。それは、大企業も同様である。
更に、自称労働者であり労働者の成れの果ての個人経営者も衰退の一途をたどる。
ここに、親会社損、自称労働者損、日本国損の三方損の社会が生まれる事となる。
そして、この状況の中で、人材派遣会社が事業をやったとしたら、請負契約では無く準委任契約で仕事を取って労働者に仕事をさせるという世間をなめきった会社、ブラック企業が生まれる訳である。
では、日本国に、この世間をなめきった準委任契約の会社を無くすためには、準委任の契約に多くの制限を与える事にしてしまい、派遣契約か請負契約だけにしてしまえば良さそうである。
 さて、「労働者なる言葉は古い、古い。今は、個人経営者の時代だ。我々は、会社と個人経営者の間を取り持つ人材派遣会社である。」
さて、個人経営者の時代がおとずれて、それが、準委任契約だとしたら、日本は滅ぶ。
経営者に対する罰則が、「善管注意義務」という罰の無い状態。
もし、罰するとすれば、「取引停止処分」が一番重いだけの状態。
これじゃ、罪が軽すぎる。やはり、仕事をもらった側の経営者は、準委任の「善管注意義務」ではなく、請負の「完成責任」を負わなければならない。
ISO9001に対しての責任を「善管注意義務」によって全うする事無く、また民法の請負契約の「完成責任」も負わないで、「労働者なる言葉は古い、古い。今は、個人経営者の時代だ。我々は、会社と個人経営者の間を取り持つ人材派遣会社である。」と言っていたら、そんな経営者なんて労働者よりも無責任である。
更に、仕事の完成間際に仕事を任せた個人経営者達の所に行ってみると、何も仕事ができていなくて、「どうして何もやっていないんだ。」と怒ったら、そこの個人経営者達に「言われた事だけやった。言われた事だけやった。」と今にも殺されそうな張り上げた声を聞かされ、その上、不完全な仕事に金を支払わなければならないとしたら、これはたまったものではない。そして罰則無しの「善管注意義務」。最大の罰は「取引停止処分」。これが一番重い罰だとしたら、この労働者を無くして個人経営者の時代にするという時代は、労働者に仕事をさせて働かせた時代よりもより無責任な時代が到来する事となるだろう。
 もし、個人経営者の時代が来て日本を発展させるとしたら、会社同士の契約で、いいや、経営者同士の契約で、「準委任」で良い仕事なんてあり得ないだろう。
また、罰則が、「請負業務の完成責任」だけであるのも生ぬるい。
だって、ISO9001という品質管理があるのだから。
完成責任じゃなく、ちゃんとISO9001の品質基準を守っているかどうかの方を重視する視点を元に、法律で罰則基準を作るという契約の方が重要である。
そして、この品質基準を守らない経営者がいたら、その罰則は、「善管注意義務」に基づく最大の罰である「取引停止処分」だと罰は軽すぎるだろう。もっと重い罰が必用である。
更に、ISO9001通りに仕事をしたのに、成果物に不良品が出たとしたら、なぜISO9001通りに仕事をしてそうなったかの問題追及をしてくれない経営者なんて必要無い。
そんな経営者なんて無能者である。だって、本当に管理監督業務をする能力があるかが疑わしい。特に、仕事を請け負わせる経営者に対しては、成果物やサービスに対して、常に問題発見能力、原因追及能力、問題解決能力を身に付けさせ経営の基本であるPDCAサイクルを回させるだとかという能力が必用だ。もし、そんな事ができない個人経営者ならば、親会社が自らそこの個人経営者達を管理監督して仕事をさせた方が、親会社自身が製品の品質管理に対して責任有る仕事をする事ができる。
そこで、民法には「親会社が自らそこの個人経営者を管理監督する」なる個人経営者など存在しなく、そんな個人経営者がいたとしたら、これは「派遣社員」であるという事になり、「派遣社員」とは労働法管轄の「労働者」であるという事になってくるだろう。こうやって日本国の法律は、無能な民法で言う所の個人経営者を駆逐して、労働法の管轄の「労働者」としての立場にさせた方が、親会社のためにもなるし、個人経営者のためにもなる。
そこで、「労働者なる言葉は古い、古い。今は、個人経営者の時代だ。我々は、会社と個人経営者の間を取り持つ人材派遣会社である。」言葉。
こんな事を言っている人間は、日本の産業能力を衰退させ、日本の労働者の能力を衰退させ、日本の管理監督者と経営者の責任感を衰退させ、日本の国力を衰退させる言葉である。
「派遣労働法」の改訂は、アメリカからの圧力でそうなったのならばしかたがないのならば、それと同時に、民法の規定の「準委任業務の善管注意義務」の法改定をする必用がある。それは、その法案を無くさせるか制限をいろいろと加えたりして、できるだけ事業主は「請負契約」しかできないようにさせる様にするか、更に、現代の品質基準を守らせるための科学を取り入れて運用する規定を設けた法改定が必用だろう。
そうしないと、日本の産業界は滅ぶであろう。
 もし、将来、人材派遣会社が望む、個人経営者の時代になるとしたら、最低限、この様にしたい。
最初は、「派遣契約」によって親会社から仕事をもらい、仕事のやり方を教わる。
そうやって、親会社から、仕事に関しての実力を付けさせてもらって認められる様になったら、今までの労働法で守られている「派遣契約」か民法の規定の個人経営者としての「請負契約」かを選ばせ、もし、「請負契約」を選んだとしたならば親会社の持つ「品質管理基準」通りに仕事をするという契約を結ばせて、もし、「品質管理基準」を満たさない仕事をするのならば罰則を与えるというぐらいの事をせねばならない。
この時、もし、労働者が一人前の実力を付けて金取りの良い個人事業者になりたいと願っていたら、親会社の企業も喜んでこの人材をバックアップして育ててゆくと頑張る事だろう。また、この個人事業主になりたいと欲している人材も仕事に対して頑張るから、双方にとっても良い関係になる。
また、人材派遣会社が、派遣契約での利益で満足せず請負契約を取ってゆきたいとなれば、人材派遣会社の方も、もっと、一生懸命に親会社の仕事を学んで自分のものにしてゆこうと頑張ってくれる事だろう。
韓非子の法の哲学とは、「賞と罰」によって人を動かすのであるから、これは、当然である。
そして、こうやって仕事を請け負う個人経営者がいたら、今度は、親会社と一緒に、ISO9001の品質管理基準に対しての共同研究をしたり、仕事に関していろいろと前向きなコミュニケーションしたりして、親会社と子会社とが一緒にその産業を成長させてゆくという経営者と経営者の関係が成り立っている社会作りをしてゆく事が、今後の産業界には必用なのである。
 現在の法律は、「労働に関する生産物」、「産業というシステム」という問題について運用してゆくには生ぬるい。
であるから、「派遣」、「準委任」、「請負」なる問題だけが、うろちょろして、労働という事が、そして経営という事が、いかにこの社会に貢献してこの日本国を立派にし世界を立派にするかという視点が抜けている。
最終的には、誰が責任を負える労働であるか?事業であるか?
「事業のシステム化と管理監督業によって社会を発展させる」という視点を重視して、
もう少し、産業の発展を科学的に考え、労働という事柄をシステム的に考え、産業システムを運用してゆくという事を真剣に科学的に考え、社会の発展という視点を真剣に科学的に考え、社会に貢献するという法の適用を科学を元にして真剣に考えて運用してゆく事を国家が考えてゆかねばならない。
 国家がこんな事態に陥るのは、皆、事業というものやその成果物の品質の向上につての本質を考えて法律について考える事よりも、労働者に支払う賃金や雇用の事にしか目を奪われてないで国家の法律について考えており、労働のシステム化と管理監督業の重要性を認識しないで人を使っている無能者達が多いから、それが経営者や政治家屋マスコミまで及んでいるのだから、きっと、こんな社会になってしまっているのだろう。
つまり、国家繁栄の本質とは、事業の成功と事業の成果物とサービスの品質の向上にあり、労働者の雇用や賃金は、それらが成り立ってから与えられるのが本来の姿であるのに、その本質が忘れ去られて、枝葉の労働の問題を重点的に考えようとするから、国家が転覆するのである。
派遣業務斡旋で満足せず請負契約だとか準委任契約に手を出そうとする人材派遣会社も、雇用主だとか労働者だとか、そんな視点で事業をするのではなく、もっと、その上位概念である、親会社の事業のシステムへの参加とその貢献にまで及ばないと、国家を転覆させてしまう基幹産業となってしまう事だろう。

 私は、今の準委任業務のソフトウエア会社はめぐまれていると思う。
一回目の仕事は、ウォーターフォール型の仕事の形態であるが、それ以降、同じ仕事をちょっと手間をかけてやる仕事も、以前のウォーターフォール型の仕事の形態で仕事を取ってくる。
例えば、昔の話だが、BISDNの仕事で、最初の一回目の仕事で、16本のデーターを取り扱っていた機械のソフトウエアの開発を成し遂げた後、今度は二回目の仕事として23本まで使える様に改造して欲しいなる親会社からの要望が出ていたのだった。
こんな仕事とは、以前の担当者がいれば、以前の開発していたソフトウエアのプログラムを流用して、そのまま改造して作れば、すぐに簡単に良質なソフトウエアを開発できるはずである。
そしたら、ウォーターフォール型ソフトウエア開発なんていう工数のかかる仕事なんて必用無いし、その分、納期も費用も安く仕事をやってもらえるはずなのである。
それなのに、親会社は、子会社に対して準委任の契約をし、ウォーターフォール型のプログラム開発形態を認め、そのための期間と工数分のお金を支払っていた。
子会社は、以前の開発要員のほとんどを撤退させ、代わりに何もその業務をやった事が無いプログラマーを集めて仕事をさせる。そして、親会社に対して堂々と「技術力のある技術者ですから大丈夫です。まかせてください。」と言ってのける。そして、みごと、その仕事を失敗させる事となる。
失敗の最大の原因とは何か?
子会社が、以前、仕事をしてくれた人を使って同じ仕事をさせなかったからである。
人材のたらい回しと、何もその仕事の内容を知らない人間に対して仕事を丸投げする。
ソフトウエア業界とは、こんな失敗がまかり通っている。
そして、デスマーチがどうのこうのだとか、親会社の偽装請負が法律違反だとか、子会社の経営者や、子会社の上司や、その子会社のプロジェクトのリーダー達が、仕事を与えてくれる親会社に対して、「我々は、親会社に虐げられてきた」なる事を堂々と仕事を与えてもらっているプログラマー達に言って憤慨していたりする。そして、納期が来て不出来なソフトウエアを親会社に渡した時、親会社がクレームを言うと、仕事を与えてもらっているプログラマー達やリーダーは、今にも殺されそうな声を張り上げて「言われた事だけやった。言われた事だけやった。」とがなりたてる。
準委任の契約形態でソフトウエア開発を依頼すると、こんな事は頻繁に起こる。
その最大の理由。準委任契約とは「善管注意義務」であり、仕事に関して法的な罰則が無い。例えば、メーカーが販売している自動車に不具合があるとしたら、リコールするのが当たり前である。そこには、日本国が定めた法的罰則が有るためである。
現在、ソフトウエア産業の人材が少ない事が大きな社会問題だと言われているが、もっと大きな問題は、ソフトウエア産業の契約形態が、準委任であり、「善管注意義務」だけを背負い、特に法的な罰則が無く無責任でいられるという事。これが、大きな社会問題だと言えるだろう。
法的な賞罰とは、責任感が強くて功績の高い産業の法人、及び従業員には賞を与える。
責任感が無くいい加減な仕事しかできない産業の法人、及び従業員には罰を与える。
こういう法整備が最低限必用である。
日本の産業力を強化するために。
更に産業力を強めるとしたら、あらゆる経営は科学的である事。労働品質を高める事。仕事のプロセスを重視して良い成果物やサービスを与えるための研究をする事。そのために、問題発見能力、原因追及能力、問題解決能力を元にした経営で言われている所のPDCAサイクルを回せる事。親会社と良い仕事のための研究のコミュニケーションができる事。親会社と仕事の作法と用語が一致している事。
これらの基礎ができていなければならない。
それは、企業の品質管理基準であるISO9001以前の問題である。

並列処理概論 ver2.(2/3)著者 吉田作太郎

7.タスク間通信。

 タスク間通信には、同期型タスク間通信と非同期型タスク間通信がある。
一番使われるタスク間通信は、非同期型タスク間通信である。
 同期型タスク間通信とは、サブルーチンコールの様な動き方をする。
タスク間通信には送信タスクと受信タスクがあり、同期型タスク間通信とは、送信タスクが受信タスクを起動させると受信タスクから返答が来るまで送信タスクがWAIT状態であるタスク間通信の事である。
μITRON_OSでは、ランデブが、同期型タスク間通信に相当する。
非同期型タスク間通信とは、送信タスクが受信タスクを起動させても送信タスクがWAIT状態にならないタスク間通信の事である。つまり、送ったら送りっぱなしのタスク間通信の事である。
代表的なのは、セマフォとイベントフラグである。
セマフォとは、排他制御に使われるだけではなく、カウント付きのタスク間通信に使われる。
また、応用プログラムとして、「タスクの起床待ち(タイムアウトの有無)、タスクの起床要求のキャンセル、タスクの起床の命令」も非同期型タスク間通信である。
さらに、これらの応用プログラムとして、データーキュー(1ワードのデーター通信)とメールボックス(アドレスポインターのデーター通信)とメッセージバッファ(可変長サイズのデーター通信)がある。送信タスクと受信タスクの間で送るデーターがいっぱいの時、送信タスクをWAIT状態させてしまう事がある点では、一見、同期型通信であるかのようでありあいまいであるが、これはタスク間通信のために同期させているのではないので、一応、設計の段階では送りっぱなしのタスク間通信とみなし、非同期型タスク間通信と呼ぶ。
非同期型タスク間通信とは、送信タスクと受信タスクとの間にタスク間通信オブジェクトがあり、通常、受信タスクはタスク間通信オブジェクトの受信待ち命令をコールする事によってWAIT状態になっている。このタスク間通信オブジェクトに送信タスクが送信要求をするとそれぞれのタスク間通信オブジェクトのサービスに従って受信タスクにある受信待ち命令はWAIT状態を解除してRUN状態になりそのサービスを受け取るという仕組みになっている。
 次に、アプリケーションのプログラム開発上、設計する時、設計する人間の思考上では、一般的な非同期型タスク間通信は、1対1が多い。

7.1.非同期タスク間通信の機能とそれを活用する命令の一覧。
これから解説する非同期タスク間通信の機能とそれを活用する命令の一覧をμITRON4.0の仕様より抜粋する。

7.1.1.イベントフラグ。
 イベントフラグの生成。cre_flg
 イベントフラグの削除。del_flg
 イベントフラグの状態参照。ref_flg
(送信用)イベントフラグのセット。set_flg (インターラプト用)iset_flg
(受信用)イベントフラグ待ち。wai_flg
         (ポーリング)pol_flg(タイムアウトあり)twai_flg
(受信用)イベントフラグのクリアー。cre_flg

7.1.2.セマフォ。
 セマフォの生成。cre_sem
 セマフォの削除。del_sem
 セマフォの状態参照。ref_sem
 (送信用)セマフォ資源の返却。sig_sem (インターラプト用)iseg_sem
 (受信用)セマフォ資源の獲得。wai_sem
         (ポーリング)pol_sem(タイムアウトあり)twai_sem

7.1.3.データーキュー。
 データーキューの生成。cre_dtq
 データーキューの削除。del_dtq
 データーキューの状態参照。ref_dtq
 (送信用)データーキューへの送信。snd_dtq (タイムアウトあり)tsnd_dtq
(ポーリング)psnd_dtq (インターラプト用ポーリング)ipsnd_dtq
   (データーキューへの強制送信)fsend_dtq
   (インターラプト用・データーキューへの強制送信)ifsend_dtq

7.1.4.メールボックス。
 メールボックスの生成。cre_mbx
 メールボックスの削除。del_mbx
 メールボックスの状態参照。ref_mbx
 (送信用)メールボックスへの送信。snd_mbx
 (受信用)メールボックスからの受信。rcv_mbx
       (ポーリング)prcv_mbx (タイムアウトあり)trcv_mbx

7.1.5.固定長メモリープールの管理機能。
 固定長メモリープールの生成。cre_mpf
 固定長メモリープールの削除。del_mpf
 固定等メモリープールの状態参照。ref_mpf
 固定長メモリーブロックの獲得。get_mpf
       (ポーリング)pget_mpf (タイムアウトあり)tget_mpf
 固定長メモリーブロックの返却。rel_mpf

7.1.6.可変長メモリープールの管理機能。
 可変長メモリープールの生成。cre_mpl
 可変長メモリープールの削除。del_mpl
 可変長メモリープールの状態参照。ref_mpl
 可変長メモリーブロックの獲得。get_mpl
       (ポーリング)pget_mpl (タイムアウトあり)tget_mpl
 可変長メモリーブロックの返却。rel_mpl

7.1.7.メッセージバッファ。
 メッセージバッファの生成。cre_mbf
 メッセージバッファの削除。del_mbf
 メッセージバッファの状態参照。ref_mbf
 (送信用)メッセージバッファへの送信。snd_mbf
       (ポーリング)psnd_mbf (タイムアウトあり)tsnd_mbf
 (受信用)メッセージバッファからの受信。rcv_mbf
       (ポーリング)prcv_mbf (タイムアウトあり)trcv_mbf

7.1.8.タスク付属同期機能。
 (送信用)タスクの起床。slp_tsk(タイムアウト付き)tslp_tsk
 (受信用)起床待ちwup_tsk (インターラプト用)iwup_tsk
 (受信用)タスク起床要求のキャンセル。can_wup

7.2.イベントフラグについて。
一般のタスク間通信のイベントフラグならば、イベントが有った事を知らせるだけであり、そのイベントが何回起こったかをカウントするカウンター機能は無い。
μITRONのイベントフラグによる非同期タスク間通信ならば、多くのタスクからのイベントを受信するための受信タスクの設計のために「多対1」の設計も、一つのタスクから多くのタスクへタスク間通信の送信をするための「1対多」の設計もありうり、それの混在型としてイベントフラグの節約のために「多対多」のタスク間通信をさせる事があるだろう。
 活用方法。(簡略化のため状態遷移の無いタスク間通信の例とする)
送信タスク側のイベントフラグの活用パターン。
① 初期処理。
② イベント感知待ち処理。イベントを感知したら③へ行く。
③ 受信タスクへ通知するメモリーエリアのデーターをセット。
④ イベントフラグのセット。set_flg
⑤ ②へジャンプ。
受信タスク側のイベントフラグの活用パターン。
① 初期処理。
② イベントフラグ待ち。wai_flg
③ イベントフラグのクリアー。cre_flg
④ セットされたメモリーエリアのデーター情報を解析して処理する。
⑤ ②へジャンプ。

7.3.セマフォについて。
 セマフォは、一般的に排他制御しかできないと思われているだろうが、これは、タスク間通信に使われる。
このセマフォのタスク間通信は、受信側タスクのセマフォのWAIT状態の解除は、送信側タスク側のセマフォのイベントをカウントしてくれるという仕組みになってタスク間通信をしてくれる。
μITRONでなくても、ほとんどのセマフォは、受信側のタスクは1つだけの設計となる。であるから、タスク間通信は、「1対1」か「多対1」にしかならない。
 タスク間通信としての活用方法。(簡略化のため状態遷移の無いタスク間通信の例とする)
送信タスクの割り込み処理のセマフォの活用パターン。
① 初期処理。
② イベント感知待ち処理。イベントを感知したら③へ行く。
③ 受信タスクへ通知するメモリーエリアのデーターをセット。sig_sem
④ セマフォ資源の返却。
⑤ ②へジャンプ。
受信タスク側のセマフォの活用パターン。
① 初期処理。
② セマフォ資源の獲得。wai_sem
③ 送信タスク側からの情報を解析して処理する。
④ ②へジャンプ。
排他制御としての活用方法。
① セマフォ資源の獲得。wai_sem
② 排他制御を必用とする処理。
③ セマフォ資源の返却。sig_sem

7.4.データーキューについて。
 これは、送信タスクからのメッセージを受信タスクに送るために使う場合が多く、「多対1」のタスク間通信をする事はできそうだが、普通、そんな設計をする人間はいなく、「1対1」のタスク間通信しかないだろう。
もし、「多対1」のタスク間通信に使うという場合、送信タスクは受信タスクに対して1ワードのデーターでコントロールするという仕様ならばあり得るかもしれない。
また、「1対多」の場合はあり得ない。その理由。送信する宛先の無いデーターキューのタスク間通信はあり得ないからである。
もし、「多対1」のデーターキューのタスク間通信がある場合、データーキューの送信する側のタスクには、データーキューがいっぱいの時はWAIT状態になる。であるから、送信タスクが複数有り、データーキューがいっぱいになった場合、送信タスクは互いにWAIT状態になってロックする事となる。これは、セマフォの排他制御と同様で有り、プロセスを設計する段階で、デッドロックに注意してジョブを設計する必用が有る。

7.5.メールボックスについて。
 これは、データーキューが、データーのタスク間通信であるのに対して、このデーターをメモリーのポインターにしたデーターキューの事をメールボックスと呼ぶ。
メールボックスの活用方法とは、次に述べるメモリープールと関連しており、トランザクションデーターによるタスク間通信に使われて、ジョブの設計において重要な位置を占める事となる知識である。
次に、データーキューと同様にメールボックスにもデッドロックが有りうる。
「多対1」のメールボックスを作った場合、プロセスを設計する段階で、デッドロックに注意してジョブを設計する事。
次に、アプリケーション開発関係者にはあまり関係無い事かもしれないが、データーキューは、メインのデーター管理をリングバッファー構造のメモリーによって実現させている。それは、タスク間通信におけるデーター通信の機能はFIFO構造のみだからである。それに対して、メールボックスは、タスク間通信におけるデーター通信の機能はFIFO順の構造か優先順位順順の構造を選べる仕組み作りになっている。このためOS側ではデーター管理方法をリングバッファー構造をとらずリンクリスト構造をとるようにしている。

7.6.メモリープール。
μITRONのメモリープールとは、OSからメモリーエリアをメモリープールエリアとして確保して、その確保したメモリープールエリアの一部をタスク間通信のトランザクションデーターとして使い、そのメモリープールエリアを貸したり返却したりするマネジメントをするために活用する。
トランザクションデーターによるタスク間通信をするジョブの設計において、一番最初にトランザクションデーターを送るタスクは、メモリープールで確保したメモリーから、使う分のメモリーエリアを借りてそれをトランザクションデーターとしてタスク間通信に活用する様に作る。このトランザクションデーターによるタスク間通信には、メモリーポインターによるタスク間通信をしているメールボックスを使う。そして、このタスク間通信で最終的にトランザクションデーターを受け付け処分するタスクには、このトランザクションデーターのメモリーエリアをメモリープールエリアへ返却する様に作っておく事。
 トランザクションデーターを送るために、メモリープールからメモリーを借りる処理は、何度もメモリープールからメモリーを借りる事ができるが、そのため借りたメモリーエリアがメモリープールで確保したメモリーを超えてしまうとWAIT状態になってしまう。トランザクションデーターを受け取ってメモリープールからメモリーを返却する処理があり、この返却によって、WAIT状態になっているメモリープールからメモリーを借りる処理が十分メモリーを借りる事ができる様になれば、WAIT状態を解除してRUN状態になりメモリープールからメモリーを借りる事ができる。
メモリープールには、固定長メモリープールと可変長メモリープールがある。
固定長のメモリープールは固定長のメモリーエリアの貸し借りをメモリープールによってでき、可変長メモリープールは可変長のメモリーエリアの貸し借りをメモリープールによってできる。
可変長のメモリープールは、可変長のメモリーの貸し借りのためにメモリーのフラグメンテーションが発生する事になり、そのフラグメンテーションを解決するために、OSは、ガベージコレクションをしなければならない。このガベージコレクションとは、ハードディスクのデフラグみたいなものであり、バラバラなメモリーエリアをいったんリニアなメモリーにしてより多くのメモリーを使いやすくするための仕組みというか機能の事である。
 さて、同じ1つの作られた(クリエートされた)メモリープールにおいて、メモリーを借りる複数のタスクがありメモリープールがメモリー不足になってしまう場合、メモリーの貸し出しをするタスクは、WAIT状態になってしまう。これは、セマフォの様な排他制御と同様のロックとして機能してしまっている。このため他のセマフォの排他制御と同等に考えて、プロセスを設計する段階で、タスクのデッドロックについて注意してジョブの設計をする事。
 次に、プロセスを設計する段階においての注意する視点を述べる。
メモリープールを活用した設計においての考察だが、1つのジョブに対して1つのメモリープールしか対応ない場合、メモリープールによる排他制御の問題点が無く、メモリープールがらみのデッドロックや優先順位の逆転現象は発生しないだろう。
複数のジョブに対して1つのメモリープールが対応している場合、メモリープールがらみによる排他制御の問題点が発生する可能性が高くなってくるだろう。
このため、オブジェクト指向設計において、できるだけタスク間通信において1つの作られたメモリープールを活用している一連のタスクの流れであるジョブは、1つのオブジェクトとみなしてグループ化して設計をして、デッドロックや優先順位の逆転現象が発生するかどうかを確かめた設計を心がける事。

7.7.メッセージバッファについて。
 これは、メールボックスとメモリープールによって作られたタスク間通信である。
これは、送信タスクからのメッセージを受信タスクに送るために使う。だからタスク間通信は「1対1」と「多対1」がありえ、「1対多」はあり得ない。送信する宛先が無いタスク間通信には使えないからである。
メッセージバッファのタスク間通信は、「多対1」にする場合、複数の送信する側のタスクに排他制御が働いてWAITする可能性がある。これは、複数の多くの送信する側のタスクがメッセージを送った時、メッセージバッファにメモリープールされているメモリーエリアが不足する事があり、このため多くの送信する側のタスクに排他制御のロックがかかるためである。であるから、プロセスを設計する段階で、このオブジェクトを含めたタスクのジョブの設計が、この排他制御について考慮してデッドロックや優先順位の逆転現象が発生しない設計をする様に心がける事。
また、ガベージコレクションによって送信する側のタスクが長時間待たされる場合もあるから注意して使う事。

7.8.タスク付属同期機能を使う場合について。
 まず、μITRONの命令を記述する。
slp_tsk タスクの起床待ち。
tslp_tsk タスクの起床待ち(タイムアウト付き)
wup_tsk ,iwup_tsk タスクの起床要求。
can_tsk タスクの起床要求のキャンセル。
まず、タスクの起床待ち命令は、タスク間通信の受信側のタスクに使われる。タスクの起床要求命令はタスク間通信の送信側のタスクに使われる。このタスク間通信は、セマフォと同様、タスクの起床要求を受け入れるとそれをカウントして、その分、WAIT状態を解除してくれる。
タイムアウト付きタスクの起床待ち命令は、この命令に設定した時間が来るまでWAIT状態になっているか、起床要求が来るまでWAIT状態を維持し続ける様になっている。
can_tsk タスクの起床要求のキャンセル命令は、タスク間通信にセマフォの様なカウンターが欲しくなくイベントフラグの様に使いたい時に使う。使い方は、タスクの起床待ち命令の後すぐにタスクの起床要求のキャンセル命令を実行すれば良い。
この命令の使い方は、受信側のタスクは1つだけの設計となる。であるから、タスク間通信は、「1対1」か「多対1」にしかならない。
(注意)タスク付属同期機能は便利だが、複雑な設計になってくると、これは、タスク間通信のメインには使えない命令である。であるからタスク間通信ライブラリーに使ってはいけない。例えば、一つのタスクにタスク間通信によってWAIT状態が発生する処理と、状態遷移図を書いて設計した他のタスクへ実行権を渡すためのタイマーWAIT処理が混在している処理を設計する場合、このタスク付属同期機能一つでまかなおうとすると、間違い率の高い設計になりやすい。この場合、タスク間通信用のオブジェクトはタスク付属同期機能に入れないで設計するべきである。そしてタスク付属同期機能は他のタスクへ実行権を渡すためのタイマーWAITとその補助のために使うのがベストである。

7.9.各タスク間通信に付随するポーリングとタイムアウトなどの解説。
 今まで述べてきたタスク間通信用の命令に、ポーリングとタイムアウト機能があるものがある。ポーリング機能の有るタスク間通信命令には、「p」が命令の名前の先頭に付随され、タイムアウト機能のあるタスク間通信の命令には「t」が命令の名前の先頭に付随されている。
これら「p」が付くタスク間通信の命令は、WAIT状態を引き起こすタスク間通信する命令について、本来はWAIT状態になるかならないかを判別してその判別結果についての値を返すための命令に変えましたという意味として、「p」を使っている。つまり、本来はWAIT状態になるはずなのを監視(ポーリング)だけで済ますために作られている。
次に、「t」が付くタスク間通信の命令は、WAIT状態が発生するタスク間通信の命令に使われ、WAIT状態になった時、一定時間を経過してタイムアウトになったらWAIT状態を解除してRUN状態になるぞという意味として、「t」を使っている。
その他、「f」も有り、これは、データーキューへの送信がいっぱいになった時、強制的に1ワードのデーターをデーターキューのバッファーに書き込むぞというための命令として使われている。

7.10.コンテキスト処理と非コンテキスト処理という用語について。
これは、別名、コンテキストの事をタスク・コンテキスト。非コンテキストの事を非タスク・コンテキストと呼ぶが、ここでは、コンテキスト、非コンテキストと呼ぶ事にする。
インターラプトという割り込み処理の事を非コンテキスト処理と呼び、その処理を行うプログラムは、ハンドラ、割り込みサービスルーチン、タイムイベントハンドラ(周期ハンドラ、アラームハンドラなど)などがある。割り込み処理ではない一般のタスクの処理の事をコンテキスト処理と呼ぶ。
一般のタスク間通信は、コンテキスト処理である。割り込みの無い処理と割り込みの無い処理のタスク間通信である。
しかし、プログラムを作って行くと、割り込みのある処理からタスク間通信の送信をしてコンテキスト処理のタスク間通信の受信処理に働きかけたい事がある。
この場合、割り込みのある処理、つまり非コンテキスト処理は、必ずタスク間通信の送信側になる。いいや、送信側しかなれない。そして、コンテキスト処理の受信処理に働きかける。
さて、このタスク間通信の送信側は、受信タスクをRUN状態にはできない。その理由。割り込み処理中であり今すぐ簡単に割り込み処理を終了する事ができないからだ。また割り込み処理を終えてからRUN状態にさせたい所だが、それができないので、その代替処理としてWAIT状態にある受信タスクをREADY状態にさせる。(もしRUN状態とREADY状態ならばそのまま)そして、後で、コンピューターが非コンテキスト状態からコンテキスト状態に変わった時、OSが、タスクのレディーキューを見てOSのスケジューリングに従ってRUN状態にさせるのである。この仕組みの事を遅延ディスパッチと呼ぶ。
μITRONの非コンテキスト用の命令には、文字の先頭に、「sns_」と「i」となっていると言われているが、非同期型タスク間通信のオブジェクトへの送信命令は、必ず「i」が付いている。
イベントフラグのセット「iset_flg」。セマフォの返却「iseg_sem」。
データーキューへポーリングしながら送信「ipsend_dtq」。
データーキューへの強制送信「ifsend_dtq」。
残念ながらインターラプト時は、データーキューへの共生送信は有っても単なるデーター送信はなかった。
また、さすがに、メールボックスは、非コンテキストは無かった。
タスクの起床「iwup_tsk」。
待ち状態の強制解除(これは設計上使ったら危なくて使えなさそう)「irel_wai」。
 さて、私ならば、RS232Cの受信割り込みデーターを受信タスクへと橋渡しする非同期式タスク間通信オブジェクトを作る時、セマフォを使いたい。そして、STXからETXまでの正常な電文をデーターキューの様なバッファーに蓄積してそのバッファーに存在する電文をセマフォによってカウントさせたい。このカウントは異常電文はバッファーから削除させるのである。また、電文に電文内容クリアー電文がやって来たら、バッファーをクリアーして非コンテキスト処理の方から受信タスクへメモリーエリアを介してクリアフラグでもセットさせたい。この時、受信タスクは多すぎるセマフォのカウンターの値の処理をする事となるが、その時は、無いデーターの場合受信するセマフォを空読みさせれば良いだろう。タスク間通信は、システムから与えられた以外に、作る専門性の高いアプリケーションのためにセマフォやイベントフラグを活用して特殊なタスク間通信オブジェクトを作成する技量がなければならないだろう。
その様な新たなタスク間通信オブジェクトの作成をする場合、C言語では無理で、C++の様なオブジェクト指向言語でなければ対応できないと考える。


8.シングルタスクによるマルチタスクの実現方法。

 プログラムに大きなループを作って、各タスクにはタスク間通信用のタスクスイッチを配備するという構造になってくる。
まずは、ジョブ内部の処理の流れを次の様にする。

8.1.ジョブの設計。

タスク起動処理→タスクA→タスクB→タスクC

8.2.全体を動かすフロチャートの作り。

① 初期処理A。タスクAのタスクスイッチをOFF、状態遷移図の変数とエラー状態の変数をゼロに設定。
② 初期処理B。タスクBのタスクスイッチをOFF、状態遷移図の変数とエラー状態の変数をゼロに設定。
③ 初期処理C。タスクCのタスクスイッチをOFF、状態遷移図の変数とエラー状態の変数をゼロに設定。

④ タスク起動処理。

⑤ タスクAのタスクスイッチがOFFならば、⑨へ行く。
⑥ 整数であるタスクの状態遷移図の変数の値に従って、タスクA内にある各処理へサブルーチンコールする条件ジャンプを実行する。
⑦ この状態遷移図の変数の値に従った各処理へのサブルーチンコールを終了したら、その処理がエラーコードを設定したらエラー処理を実行できる様に作る。
⑧ もしエラーが無ければ次の処理を実行。

⑨ タスクBのタスクスイッチがOFFならば、⑬へ行く。
⑩ 整数であるタスクの状態遷移図の変数の値に従って、タスクB内にある各処理へサブルーチンコールする条件ジャンプを実行する。
⑪ この状態遷移図の変数の値に従った各処理へのサブルーチンコールを終了したら、その処理がエラーコードを設定したらエラー処理を実行できる様に作る。
⑫ もしエラーが無ければ次の処理を実行。

⑬ タスクCのタスクスイッチがOFFならば、⑰へ行く。
⑭ 整数であるタスクの状態遷移図の変数の値に従って、タスクC内にある各処理へサブルーチンコールする条件ジャンプを実行する。
⑮ この状態遷移図の変数の値に従った各処理へのサブルーチンコールを終了したら、その処理がエラーコードを設定したらエラー処理を実行できる様に作る。
⑯ もしエラーが無ければ次の処理を実行。
⑰ ④へ行く。

8.3.全体の動きについての説明。

タスク起動処理によってタスクAのタスクスイッチをONにする。
するとタスクAが動き出す。
ここで、タスクAが次の処理を起動させたかったらタスクAはタスクBのタスクスイッチをONにしてからタスクAの状態遷移図の変数をゼロにして初期設定しながらタスクAのタスクスイッチをOFFにする。
するとタスクBが動き出す。
ここで、タスクBが次の処理を起動させたかったらタスクBはタスクCのタスクスイッチをONにしてからタスクBの状態遷移図の変数をゼロにして初期設定しながらタスクBのタスクスイッチをOFFにする。
するとタスクCが動き出す。
ここで、タスクCが次の処理を終了させたかったら、タスクCの状態遷移図の変数をゼロにして初期設定しながらタスクCのタスクスイッチをOFFにする。
この様にシングルタスクにおいて、タスクスイッチがタスク間通信の役割を果たす。


9.並列処理による高速化。

 今、とある処理にかかる時間が、均一に1回という時間がかかるとする。

以下の様な一連の作業を成し遂げるシングルタスクがあったとする。
開始→(処理1)→(処理2)→・・・・・・→(処理10)→終了
10の処理を100回する場合、シングルタスクの場合、10*100=1千回の時間がかかる。
10の処理を1000回する場合、1万回の時間がかかる。
 以下の様な一連の作業を成し遂げる並列処理があったとする。
          ┌→(処理1)――┐
          ├→(処理2)――┤
   (開始)―――┤   ・    ├―――(終了)
・   ・    ・
・   ・    ・
          └→(処理10)―┘
これを、並列処理によって10の処理を並列的に実行させている。この作業を100回する場合、100回の時間がかかって終了する。
この作業を1000回する場合、1000回の時間がかかって終了する。
 以下の様な一連の作業を成し遂げる並列処理があったとする。
開始→(処理1)→(処理2)→・・・・・・→(処理10)→終了
これを、並列処理によって10の処理を直列に接続させて、この作業を100回する場合、100+9回の時間がかかって終了する事になる。
この作業を1000回する場合、1000+9回の時間がかかって終了する。
これをCPUに例えて言うならば、パイプライン処理、または、バケツリレー方式、ベルトコンベア方式による高速化と呼べるだろう。
これは、ジョブの高速化である。
ここから、ジョブをタスクに分けて、タスクを並列に接続しても、タスクを直列に接続してベルトコンベア方式によって流しても、ジョブを動かす回数が多ければ多いほど、時間を近似すれば同じ時間しかからない事となる。
では、ジョブの設計は、デバッグも含めると、タスクを並列的に接続する構造は並列化しているタスクをいっぺんにタスクを動かしてデバッグしなければならないので複雑である事に対して、直列に接続する方法は順番に一つずつタスクをデバッグしてゆけば良いので単純で確実なデバッグをしやすい。
この事から、プロトタイプのジョブの設計では、並列処理を全て数珠つなぎにした1次元のタスクの流れにした方が、並列処理の高速化をある程度含めて間違い率の少ないプログラム開発をする事ができる。
そして、このプロトタイプの設計が成功したら、今度は、並列化した方が高速化が図れる場所を並列化して設計し直す事で、本当の並列処理を生かした完璧なプログラムを作るというプログラム開発する作戦が考えられる。


10.マルチコアの意味。

 一般のマルチタスクとは、シングルCPUによって全てのタスクを動かすものであり、それは、一人の人間によって全てのジョブをこなすというものである。
マルチコアによるマルチタスク処理とは、複数のCPUによって全てのタスクを動かすものであり、それは、複数の人間によって全てのジョブをこなすものである。
マルチコアで、処理が早くなるかどうか?
これは、システム次第である。設計次第である。設計のアルゴリズム次第である。
1CPUで済む処理をマルチコアのCPUを使っても処理の高速化は無意味である。


11.スーパーコンピュータ。

 多くの場合、3次元データーの高速化であり、シミュレーションに使われる。
気象データーであったり、流体力学に基づいた計算であったりする。
3次元データーの一つのセルを1タスクとして、各タスクがタスク間通信によって立体的に結ばれ、それが、マルチコアによって並列計算されているという構造である。更に、このマルチコアのCPUが、3次元上に立体的に配置されており隣り合ったCPUに対してCPU間通信をして、巨大な3次元空間の演算をしていると考えられる。

参考:
題名:杉本大一郎 著、手作りスーパーコンピュータへの挑戦 テラ・フロップス・マシンを目指して、講談社ブルーバックス

並列処理概論 ver2.(1/3)著者 吉田作太郎

マルチタスクを使ったプログラミングにオブジェクト指向設計のグループ化を組み入れた設計作法についての考察。


著者:吉田作太郎

2014/06/14





並列処理概論 ver2.

はじめに
これは、OSを作るための本ではなく、マルチタスクOSを利用してプログラムを作る事を第一の目的とした本である。第二の目的は、オブジェクト指向のグループ化の性質を利用してマルチタスクで動くプログラム設計の手法を学習するための本である。
まず、私が初めてマルチタスクを理解する足がかりとなったものは、セマフォを使ったタスク間通信のサンプルを理解する事から始まった。これによってマルチタスクにおけるプログラミングとは、タスク同士の連係プレーによって成される事を理解できた。次にこのタスク間通信の部分をオブジェクト指向設計のオブジェクトにしてみた。すると、オブジェクト指向の有効な活用方法を理解する事ができた。これが、私が初めて同時にマルチタスクとオブジェクト指向を理解するきっかけとなったのであった。

なお、このver2は、ver1に対して、特にTRON OSの仕様に基づく内容を加え編集した。

前書 並列処理の概略
(メカニズムの説明と設計とその可能性について述べる)
なぜ、並列処理であるマルチタスクが必要であるか?
複数の装置が順番に一つずつ動いて一連の動作をしているとする。
シングルタスクでは、それ以上の動作をさせる事はできない。
しかし、マルチタスクを使った設計では、順番管理をしながら、一つ一つの装置が確実に順番通りに動きながら同時に複数の装置を隙間なく動かす事ができる。
それは、CPUの計算速度の高速化のためではなく、複数の装置の処理の連係プレーの1セッションの高速化のためにマルチタスクがある。
そして、それをふまえて、マルチタスクを活用した設計は、並列処理できるタスクの連携プレーのセッションの数を容易に増やして、高度な並列処理を実現させる事が可能になる。このタスクの連係プレーの実現のためには、タスクとタスクの間には、さまざまな形のタスク間通信が使われている。
私の並列処理の基本設計の設計作法は、DFDとオブジェクト指向のシーケンス図である。
それは、ハードウエアの振る舞い方も同時に記述する事が可能である。
しかも、今、これからのCPUは、マルチコアの時代に突入しようとしている。
マルチタスクの設計作法が分かれば、その基本は、マルチコアにも生かされる。
マルチタスクOSにおいて、シングルコアCPUはRUN状態が1つに対して、マルチコアCPUは、RUN状態がコアの数の分だけ持てる事が特徴である。
そして、このマルチタスクを用いたシステムの設計の基礎が分かれば、その応用は、あらゆる並列処理を記述する事が可能となる。
例えば、データー通信によるネットワークによって機能分割され分散統合されたシステム。
また、複数CPUを搭載したハードウエアのシステム。
そのシステムの構成と振る舞いを並列処理として記述する事ができるだろう。
 さて、並列処理の設計の重大な問題は、「デッドロック」である。その他にマルチタスクは、優先順位を持つため「優先順位の逆転現象」の問題を抱えている。これは、共に排他制御から生まれる問題である。
私は、並列処理特有のこれら排他制御についての問題点回避のための考察し、並列処理のプログラミングの設計あり方について考察している。
その他にも、並列処理のプロトタイプの設計についてのあり方の考察などをしている。
そして、各種問題解決型の設計のパターン化についても考察をしている。



目次
1.プロセス、ジョブ、タスク。 4
2.タスクの構成。 4
2.1.処理の流れ。 4
2.2.他のタスクへ実行権を渡すためのWAIT状態にする処理。 5
2.3.編集処理のタスクの優先順位を低くさせる意味。 6
3.ジョブの設計。 6
3.1.業務フロー型のジョブの設計のパターン。 7
3.2.オブジェクト指向型のジョブの設計のパターン。 7
4.プロセスの設計。 9
4.1.デッドロック発生のメカニズム。その1。(理論) 9
4.2.デッドロック発生のメカニズム。その2。(装置) 10
4.3.デッドロック発生のメカニズム。その3。(データーベース) 10
4.4.排他制御の問題点。 11
5.タスク間通信とトランザクションデーター。 12
6.ランデブ。 13
7.タスク間通信。 14
7.1.非同期タスク間通信の機能とそれを活用する命令の一覧。 14
7.1.1.イベントフラグ。 14
7.1.2.セマフォ。 14
7.1.3.データーキュー。 15
7.1.4.メールボックス。 15
7.1.5.固定長メモリープールの管理機能。 15
7.1.6.可変長メモリープールの管理機能。 15
7.1.7.メッセージバッファ。 15
7.1.8.タスク付属同期機能。 15
7.2.イベントフラグについて。 16
7.3.セマフォについて。 16
7.4.データーキューについて。 17
7.5.メールボックスについて。 17
7.6.メモリープール。 17
7.7.メッセージバッファについて。 18
7.8.タスク付属同期機能を使う場合について。 18
7.9.各タスク間通信に付随するポーリングとタイムアウトなどの解説。 19
7.10.コンテキスト処理と非コンテキスト処理という用語について。 19
8.シングルタスクによるマルチタスクの実現方法。 20
8.1.ジョブの設計。 20
8.2.全体を動かすフロチャートの作り。 20
8.3.全体の動きについての説明。 21
9.並列処理による高速化。 22
10.マルチコアの意味。 22
11.スーパーコンピュータ。 23
12.チケットプリンターを作った時の例。 23
13.労働について考える。 26



1.プロセス、ジョブ、タスク。

マルチタスクのプログラム設計を理解するために書く。
このプログラム設計にオブジェクト指向設計によるグループ化を行って並列処理に関して考察する。
ここでは、タスクの連係プレーを多彩に掲載する。
この連係プレーを理解する事により、マルチタスクOSを用いたシステム設計の基礎の理解でき、その理解から日常の労働の業務について、次の様な事を理解する能力が身に付き、日常の労働をシステムとして理解し改善改良できる能力が得られる。
○ タスクレベルの理解。
○ ジョブレベルの理解(タスク同士の連係プレー)。
○ プロセスレベルの理解(ジョブ同士の連係プレー)
プロセスレベルの理解では、排他制御の問題点であるデッドロック、優先順位の逆転減容についても解説する。
 さて、プロセス、ジョブ、タスクについて解説する。
システム全体の運動をプロセス。
プロセス内部の仕事の一連の流れをジョブ。
ジョブを細かくして仕事の一部分の作業(処理)の事をタスクと呼ぶ。
つまり、ジョブとは、業務フローの形として表され、タスクという作業の流れ図の1セッションの集まりの事である。
ジョブが集まった全体の仕事の事をプロセスと呼ぶ。
並列処理の設計とは、コンピューターのプログラミングにおいて、この世のプロセスが全て並列的に動いている事を前提にシステム設計するという方法論である。
プロセスが並列処理なのだから、その下の概念のジョブも並列処理である事は当然であり、また、そのジョブの下の概念であるタスクも並列処理を行っている並列処理における最小単位である。


2.タスクの構成。

初期処理を終えたタスクの処理の流れとは、状態遷移図に従って実行されるように設計する。
 並列処理におけるタスクとは、まずは、初期処理をし、次に状態遷移図に従って常に循環系のループとして動く構造をしている。
それは、まず、最初は、イベントが来るまでWAIT状態として停止している。
そのタスクを動かすイベントが発生したらWAIT状態を解除してタスク内の状態遷移図の変数に従ってその状態における処理をして、また、このタスクの状態遷移図の初期状態の変数の値にもどってイベントが来るまでWAIT状態として停止する処理を再度実行する。タスク構成はこの様なループ構造の処理となっている。

2.1.処理の流れ。

①  実際のタスクの設計の構造とは、ます、初期処理があり、そこでタスクの状態遷移図の変数と、タスクのエラー状態の変数を、ゼロに初期設定する。
② 初期処理を終えると、整数であるタスクの状態遷移図の変数の値に従って、各処理へサブルーチンコールする条件ジャンプを実行する。
③ この状態遷移図の変数の値に従った各処理へのサブルーチンコールを終了したら、その処理がエラーコードを設定したらエラー処理を実行できる様に作る。
④ もし、エラーが無ければ、「他のタスクへ実行権を渡すためのWAIT状態にする処理」を実行する。
⑤ ②へループする。
タスクの設計図によって設計されている状態遷移図の中に、「イベントが来るまでWAIT状態として停止する処理が入っている。
その処理を実行する状態遷移図の変数の値とは、ほとんどがゼロである。
この状態遷移図には必ずドキュメントとしてマトリックスを付加させる事。
さて、このタスクの状態遷移図の変数は、オブジェクト指向設計では、このタスク専用の属性として取り扱う事。すると、デバッグ時、状態遷移図の変数の値を参考にしやすいのと同時に、このタスクと、タスクに使われる状態遷移図の変数を利用しているサブルーチンも、同じオブジェクトの属性の変数として取り扱われ、プログラミング中、参照しやすくなってくる。

2.2.他のタスクへ実行権を渡すためのWAIT状態にする処理。

 これは前節「2.1.処理の流れ」の④の部分の詳細の解説である。
言いたい事は、「タイマーウエイト」にするか、「ラウンドロビン型OSならば、ローテーション・レディーキュー」にするかのどちらかである事。
それと、ラウンドロビン型OSにおいての、ローテーション・レディーキューの使い方について詳しく解説している。

 プログラマーのミスでビジーループの処理があった場合、本来ならばここのRUN状態をREADY状態にするためにμITRON_OSで使われているローテーション・レディ―キュー(rot_rdq)を使いたい所だが、もし、自タスクの優先順位(プライオリティー)が高い場合、マルチタスクOSのディスパッチ(タスク切り替え)部分はREADY状態にした後すぐにRUN状態になってしまうので、他の優先順位の低いタスクに仕事を回す事ができなくなる。
このため、この部分はタイマーWAITさせる事によって他の優先順位の低いタスクにも仕事を回させるようにする方法をとらねばならない。
しかし、プライオリティーなる優先順位なるものが存在しない簡略化したマルチタスクOS環境ならば、WAITする状態を無くしてRUN状態とREADY状態しかないOSを作っても役に立つ。この様なOSの事をラウンドロビン型OSと呼ぶ。ラウンドロビン型OSにおいてWAIT状態を作りたかったら、自タスクにタスクスイッチ付ける。ここで自タスクをWAIT状態にしたい場合、自タスクのタスクスイッチをONにして、ローテーション・レディーキュー命令を実行する。このタスクのWAIT状態を他のタスクが開放させてRUN状態にさせたかったらこのタスクのタスクスイッチをOFFにしてローテーション・レディーキュー命令を実行させるのではなくタスク内の処理をさせれば良い。もしタイマーWAIT処理を作りたかったらこのタスクスイッチの応用として、CPUに接続されているタイマーICの時間を計測してWAITする時間内ならばローテーション・レディーキュー命令を使ってREADY状態にさせWAITする時間を経過した後ならばローテーション・レディーキュー命令を止めてRUN状態にさせるように作っておけば良いのである。
 さて、ローテーション・レディーキュー命令には、インターラプト(ハードウエア割り込み)用がある。この使い道だが、μITEON_OSの割り込み処理には、「割り込みハンドラ」と「タイムイベントハンドラ(周期ハンドラ、アラームハンドラ)」がある。
使い道はただ一点、ラウンドロビン型OSをTSS(タイムシェアリング・システム)型OSにするために、タイマーIC割り込み制御のための周期ハンドラの一つに、割り込み発生周期時間の設定とインターラプト用ローテーション・レディーキュー(irot_rdq)命令を挿入し割り込み処理を終了した後すぐにディスパッチするための命令(disp)を使うためにある。この周期ハンドラとは、その他、ウォッチドッグタイマーを作るためにも使われる汎用性の高い時間管理処理である。
μITRONでは、インターラプト用も含めてローテーション・レディーキュー命令はあまり使われない状態にあるらしい。理由は、組み込み用なので、TSSは必要ないし、優先順位を付けたラウンドロビン型タスクにおいては、ローテーション・レディーキューの実装は作りづらいし、開発側は間違いやすいためかもしれない。
ところで、μITRONを元にしたH8マイコンのSmalight_OSの仕様では、優先順位の一番低いタスクは、ラウンドロビン型タスクであり、インターラプト用のローテーション・レディーキュー命令もそうでないのも使えるようになっている。
もし、H8マイコンのSmalight_OSを使う場合、RUN、READY状態しか無いラウンドロビン型OSを目当てとした一番軽いOSとして使いたい。もちろん、ローテーション・レディーキュー命令がある事が目当てである。それは、RAMの容量を少なくしたいためである。
更に、ラウンドロビン型のマルチタスクOSの利点というか特徴は、タスク間通信用の命令を使わなければ絶対OS側のWAIT状態になる事は無い。ただ、各タスクに組み込んでいるローテーション・レディーキュー命令によって各タスクを切り替えているだけであり、排他制御が必用な並列処理にまで及んでいない。つまり、まだまだシングルタスクもどきなので、排他制御は必用無いので、排他制御に伴うデッドロックの問題や優先順位の逆転現象の問題が発生しない。そして、これが、ラウンドロビン型のマルチタスクのシステム設計においての最大の利点となってプログラム設計をする事ができるのである。
 他、Smalight_OSよりももっと軽いラウンドロビン型OSを作るとしたら、レディーキューを無くしてしまって、固定したタスクを順番に実行する型のOSを作る事も考えられる。その場合、レディーキューが無いので、「ローテーション・レディーキュー」の命名はそうではない名前になるだろう。命名は、きっと、「タスク・ローテーション」か「リターン」あたりが妥当と考える。

2.3.編集処理のタスクの優先順位を低くさせる意味。

 編集処理とは他のタスクへ実行権を渡すという処理をほとんどする事ができず、しかも処理が長すぎる。そのため他の時間スケジュールの厳しいタスクにRUN状態の実行権が渡らなくなる事態が生じる事となる。
この事態が生じないための回避する仕組みというべきか作戦として、わざと編集処理は優先順位を低くして他の時間スケジュールの厳しいタスクに実行権のほとんどを渡しスケジュールが厳しいタスクの処理が終わったら、自編集処理を継続的に実行してもらう事にする。
ここで、他の装置の通信のための送受信タスクとは、どの教科書にも優先順位が高い様に設計する事がセオリのようであるが、送受信タスクの中にデーターを編集する作業があるのならば、そのタスク内のこの作業に関してだけ、優先順位を低く設定した方が良いだろう。そうしないと、時間スケジュールの厳しい他のセンサーをポーリングして監視しているタスクを長期間待たされる事となってシステムが誤動作する原因を作る可能性を高くするからである。
優先順位を低くする方法論とすれば、優先順位の低いランデブポートのタスクを使うか、長期間の編集処理を始める時、優先順位をわざと低くさせてその処理を実行した後は元の優先順位を元に戻すという方法論が考えられる。


3.ジョブの設計。

 ジョブの設計とは、構造化設計では、DFDによって表現される。
また、オブジェクト指向設計においては、シーケンス図かアクティビティー図が使われる。
更に、オブジェクト指向設計ならば、タスクとタスクの間に、タスク間通信のオブジェクトか、タスク間通信を伴ったDB(データーベース)のオブジェクトを追加してプロセスを通してデーターの流れで表現させる方法を使う。

3.1.業務フロー型のジョブの設計のパターン。

タスク1→タスク2→タスク3→タスク4

始めは、全てのタスクはWAIT状態であった。
タスク1が起動して処理を終えたら、WAIT状態であったタスク2が起動した。
起動したタスク2の処理を終えたら、WAIT状態であったタスク3が起動した。
起動したタスク3の処理を終えたら、WAIT状態であったタスク4が起動した。
タスク4の処理を終えたら全てのタスクはWAIT状態になってしまった。
こういうストーリーが考えられる。

3.2.オブジェクト指向型のジョブの設計のパターン。

 ここでは、タスクもメールボックスもデーターベースも、一つのオブジェクトとして取り扱う。
(例1)
タスク1→メールボックス1→タスク2→メールボックス2→タスク3→メールボックス3→タスク4
まず、始めに、全てのタスクはWAIT状態であった。
タスク1が起動して処理を終える時、メモリープール機能によってOSからメモリーエリアを借りてそのメモリーエリアをタスク間通信用のトランザクションデーターにする。そして、そのトランザクションデーターにデーターを書き込みした後、タスク間通信のオブジェクトであるメールボックス1にトランザクションデーターを設定して送るとタスク2はメールボックス1からトランザクションデーターを受け取りながらWAIT状態を解放する。その後タスク1の状態遷移の変数を初期状態にする。
タスク間通信によってタスク2のWAIT状態が解放されRUN状態になって起動すると、自タスクの処理をほどこしながら受け取ったトランザクションデーターのデーターを読み書きし、自タスクの処理を終える時、タスク間通信のオブジェクトであるメールボックス2にトランザクションデーターのポインターを設定して送るとタスク3はメールボックス2からトランザクションデーターを受け取りながらWAIT状態を解放する。その後タスク2はメールボックス1からのトランザクションデーター待ちになってWAITする。この時タスク2の状態遷移の変数は初期状態となる。
タスク間通信によってタスク3のWAIT状態が解放されRUN状態になって起動すると、自タスクの処理をほどこしながら受け取ったトランザクションデーターのデーターを読み書きし、自タスクの処理を終える時、タスク間通信のオブジェクトであるメールボックス3にトランザクションデーターのポインターを設定して送るとタスク4はメールボックス2からトランザクションデーターを受け取りながらWAIT状態を解放する。その後タスク3はメールボックス2からのトランザクションデーター待ちになってWAITする。この時タスク3の状態遷移の変数は初期状態となる。
タタスク間通信によってタスク4のWAIT状態が解放されRUN状態になって起動すると、受け取ったトランザクションデーターを読みながら自タスクの処理をし、自タスクの処理を終える時、受け取ったトランザクションデーターをメモリープール機能から借りたメモリーエリアを返却する。その後タスク4はメールボックス3からのトランザクションデーター待ちになってWAITする。この時タスク4の状態遷移の変数は初期状態となる。

(例2)
タスク1(writ)→DB1→(read)タスク2(writ)→DB2→(read)タスク3(writ)→DB3→(read)タスク4

始めは、全てのタスクはWAIT状態であった。
タスク1が起動して処理を終える時、タスク間通信を伴ったDB1にデーターを書き込んでからタスク2のWAIT状態を解放する(タスク間通信する事)、その後タスク1は起動待ちになるためにタスク1の状態遷移の変数を初期状態へ戻す。
タスク2のWAIT状態が解放され起動したらDB1のデーターを読み込み判断してタスク2の処理を実行する。そしてタスク2の処理を終える時、タスク間通信を伴ったDB2にデーターを書き込んでからタスク3のWAIT状態を解放して(タスク間通信する事)、その後タスク2が次のタスク間通信を待つためにタスク2の状態遷移の変数を初期状態へ戻す。
タスク3のWAIT状態が解放され起動したらDB2のデーターを読み込み判断してタスク3の処理を実行する。そしてタスク3の処理を終える時、タスク間通信を伴ったDB3にデーターを書き込んでからタスク4のWAIT状態を解放して(タスク間通信する事)、その後タスク3が次のタスク間通信を待つためにタスク3の状態遷移の変数を初期状態へ戻す。
タスク4のWAIT状態が解放され起動したらDB3のデーターを読み込み判断してタスク4の処理を実行する。そしてタスク4の処理を終える時、タスク4が次のDB3からのタスク間通信を待つためにタスク4の状態遷移の変数を初期状態にする。

 DB1、DB2,DB3は、たいていは、トランザクションデーターを使ったタスク間通信用のデーターベースである。この様なタスク通信型データーベースは、一つのクラスとして表し、このクラスをC++の場合、new演算子を使って、それぞれDB1、DB2、DB3のインスタンスを生成してプログラムとして活用するものである。これが、オブジェクト指向設計のHAVEという性質を利用した便利な活用方法となる。
例)
Task_Tusin_Db_Class * db1 ;
db1 = new Task_Tusin_Db_Class ;
Task_Tusin_Db_Class * db2 ;
db2 = new Task_Tusin_Db_Class ;
Task_Tusin_Db_Class * db3 ;
db3 = new Task_Tusin_Db_Class ;

ここで、データーベースオブジェクトの役割について説明する。
DB1とは、タスク2をWAITさせる役目とタスク1によってタスク2のWAIT状態を解放させ起動させるという仕組みが整っている。このためDB1は、これを「タスク間通信」するオブジェクトの部品と呼ぶ。こでは、DB2、DB3も同様に、「タスク間通信」するオブジェクトの部品と呼ぶ。

 タスク間通信に使われるデーターベースオブジェクトの例を示す。
マルチタスクOSで、セマフォを使う場合、その多くのDBはFIFOである。たまに、「FIFO+タスクの優先順位」なるものがあるかもしれないが、これは例外に近い。
マルチタスクOSで、イベントフラグを使う場合、その多くのDBはフラグ制御されたデーターベースである。

全てのタスク間通信に使われるデーターベース部分のオブジェクトは、必ず排他制御を設定する事。データーライトだけではなくデーターリード時にも排他制御をほどこす事。その最大の理由とは、1変数のリードだと問題ないと思っている人達が多いが、これが、データーアクセスのために複数の変数のリードだと途中書き込みが発生した場合、値が不定になってしまう可能性が高い。であるから、複数の数値を取り扱う場合は迷わずデーターリード時でも排他制御を使う事。
この場合、セマフォを使うのだが、どうしてもアクセスするタスクの優先順位が違って優先順位の逆転現象が起こる場合、セマフォをミューテックスに変更するという可能性を持つ。
もし、このミューテックスを使いたくなければ、このデーターベースにアクセスするタスクの優先順位を一定に保つための工夫が必要である。

 オブジェクト指向はグループ化する事ができる。
DB1とタスク2、DB2とタスク3、DB3とタスク4をグループ化して、それぞれ、タスク2、タスク3、タスク4と表現されると、このオブジェクト指向型のジョブの流れとは、3.1.で示した業務フロー型のジョブの設計のパターンとなる。


4.プロセスの設計。

 ジョブを設計して比較すると、各ジョブ内のタスクの内、同じ一つの装置を取り扱うタスクがあったりする。そして、同じ一つの装置を取り扱うのでその処理のタスクを実行するには互いに排他制御が必用である場合が多いものである。
そこで、同じ装置を取り扱うタスクをオブジェクト指向設計によってグループ化して一つのオブジェクトとすれば、一つの排他制御用のセマフォ変数を使ってグループ内のタスクの排他制御を行い、それをグループ化したオブジェクトの属性として取り扱えば良い。
この様に、排他制御とは、同一装置を取り扱うタスクの問題に使われる。その他にまた同一データーベースを取り扱うタスクの問題にも使われる。

 ここにオブジェクト指向の概念を導入してみる。
すると、同一装置を取り扱うタスクの排他制御でも、同一データーベースを取り扱う排他制御でも、同一ならば、そこをグループ化して一つの同一オブジェクトとして取り扱いその属性には一つの排他制御の変数をグループ化したオブジェクトの属性として設定しておけば良いという事になってくる。
こうやって、「3.2.オブジェクト指向型のジョブの設計のパターン。」の設計作法を活用して複数のジョブをながめて見れば、排他制御における優先順位の逆転現象とデッドロックの発見とその回避する対策も見つける事ができるようになるだろう。
また、デッドロックを発見する事ができるシミュレーターの作成も容易になってくるだろう。

4.1.デッドロック発生のメカニズム。その1。(理論)

デッドロックの発生のメカニズムとは、たいていの本には次の様な事が書いてある。
資源Aと資源Bがありました。
1つのタスクは、資源Aを排他制御でロックした後、資源Bを排他制御でロックして、その後、資源AとBとにかかった排他制御を解放しました。
もう一つのタスクは、資源Bを排他制御でロックした後、資源Aを排他制御でロックし、その後、資源AとBとにかかった排他制御を解放しました。
この時、資源AとBは、とある事象によってロックがかかる事象が発生します。
それをデッドロックと申します。
ざっと、こんな具合の話があるものだ。
私は疑問に思った、資源Aを使うためにロックしたのならば使った後に資源Aをアンロックすれば良い。そして、次に資源Bを使う時も資源Bのためにロックしたのならば使った後に資源Bをアンロックすれば良い。
これで、デッドロックは避けられると考えた。
しかし、事態はそうじゃなかったらしい。
2つの排他制御をするためにロックして使わなければならない資源があるとしたら、資源へのアクセスの順番がA→Bならば、他の資源へのアクセスの順番もA→Bでなければデッドロックを回避できない。もし、逆の事があるとしたらデッドロックが発生する。
こう述べたいのだろう。
以下、FIFO順のタスク間通信、FIFO順のセマフォによる排他制御における考察を述べる。
優先順位順のタスク間通信、優先順位順のセマフォの排他制御、ミューテックスにおける排他制御についての考察は、現段階の私にとって考察は不可能である。

4.2.デッドロック発生のメカニズム。その2。(装置)

FIFO順のタスク間通信、FIFO順のセマフォによる排他制御における考察を述べる。
次の様な2つのジョブの流れがあるとする。
タスク1→装置Xタスク1→装置Yタスク1→タスク2
タスク5→装置Yタスク2→装置Xタスク2→タスク6
そして、各装置はオブジェクト指向設計において次の様にグループ化しているとする。
「装置Xオブジェクト」は、「装置Xタスク1」と「装置Xタスク2」を持ってグループ化されており、1つのセマフォ変数をオブジェクトの属性として持ち、この2つのタスクを排他制御している。
「装置Yオブジェクト」は、「装置Yタスク1」と「装置Yタスク2」を持ってグループ化されており、1つのセマフォ変数をオブジェクトの属性として持ち、この2つのタスクを排他制御している。
以上の様だとデッドロックを発生する可能性を高くする。
回避方法は、資源のアクセス順番をそろえるためにジョブの順番を次の様にすれば良い。
タスク1→装置Xタスク1→装置Yタスク1→タスク2
タスク5→装置Xタスク2→装置Yタスク2→タスク6
これが、プロセスの設計の肝心な所である。
今回は、複数のタスクを排他制御によって制御している同一オブジェクトについて説明した。
そして、ここには、排他制御によるデッドロックの問題以外に、タスク同士の優先順位の逆転現象まで、プロセスの設計には考慮しておく必用がある。

4.3.デッドロック発生のメカニズム。その3。(データーベース)

 FIFO順のタスク間通信、FIFO順のセマフォによる排他制御における考察を述べる。
今度は、装置についてのデッドロックではなくデーターベースによるデッドロックを説明する。

まずは、タスク間通信用のデーターベースには必ず排他制御があるものとして、DBとして表現し、次の様な2つのジョブの流れがあるとする。
タスク1→DB_X→タスク2→DB2→タスク3→DB_Y→タスク4
タスク5→DB_Y→タスク6→DB2→タスク7→DB_X→タスク8
この時は、DB_XとDB_Yは、デッドロックする可能性が高いです。
特にジョブの中のタスクが隙間無く流れていれば、デッドロックになる可能性が高い。
もし、デッドロックをなくすとすれば、資源のアクセス順番をそろえるために、タスク5以下のジョブの流れを次の様にすれば良い。
タスク1→DB_X→タスク2→DB2→タスク3→DB_Y→タスク4
タスク5→DB_X→タスク6→DB2→タスク7→DB_Y→タスク8
というように、排他制御のある部分の順番を整理しなおして設計し直さなければならなくなってくる。
これが、プロセスの設計の肝心な所である。
今回は、排他制御のあるDBについて説明した。
そして、ここには、排他制御によるデッドロックの問題以外に、タスク同士の優先順位の逆転現象まで、プロセスの設計には考慮しておく必用があるのである。

4.4.排他制御の問題点。

以上、FIFO順のタスク間通信、FIFO順のセマフォによる排他制御における考察を述べた。
これは、単純な例なので、考察できるが、これが、優先順位順だとか、ミューテックスにしたら、どのようになるかは、考察不可能である。
ミューテックスにしたら、確かに優先順位の逆転現象は無くなるだろう。
ただし、プロセスの視点で、排他制御の拠点が2つ以上あるジョブにおいて、どんな現象が起こるかは考察できないであろう。
その他にも、排他制御とは、セマフォによるロック以外にも存在する。
主に並列処理のタスク間通信関連で使われる、データーキュー、メールボックス、メモリープール、メッセージバッファも、その使い方次第で、排他制御の問題が生まれ、そして、デッドロックの問題、優先順位の逆転現象の問題を発生させる可能性を持つ。
なぜ、必然性と言わないで可能性と書くか。それは、並列処理があまりいそがしくない時は、起こる可能性が少ないからである。そして、いそがしい並列処理になった時、初めて排他制御の問題点が発生する事があるという非常にやっかいな問題であるのだ。
これは、タスクの設計の視点で解決できる問題では無く、また、ジョブの視点で解決できる問題では無く、プロセスの設計にまで及んでゆかないと、大抵の排他制御の問題点は解決する事は不可能である。
もし、簡単なプロセスの設計の視点に立った時、排他制御が発生するグループ群をまず特定する事。
それは、特定のセマフォによって発生する排他制御なのか、
データーキューへの入力部分によって発生する排他制御なのか、
メールボックスへの入力部分によって発生する排他制御なのか、
メモリープールからメモリーエリアを借りる部分に発生する排他制御なのか、
メッセージバッファへの入力部分によって発生する排他制御なのか、
その排他制御を起こす資源のグループはどことどこにあるのか。
こういう事を徹底的に調べる事。
そして、人間的観察力では、どうしても能力的に排他制御の問題点が起こる部分が特定できない時は、シミュレーターのソフトを買って使い、どこと、どこに問題点があるかを特定して、問題点があるとしたら、ジョブの設計をやり直して、問題点が発生しないような工夫をする事。
複雑な並列処理を設計する事ができる技術者とは、最低限、このぐらいの知識と経験が無ければ、役に立たない。
複雑ではない並列処理の設計ならば、この様なシミュレーターを用いた設計までは必用無く、プロセス設計の視点に立って設計してゆけば問題は無いであろう。
 もし、この排他制御に対する対策のできないプログラマーが、並列処理のプログラムを作っても、負荷の少ないプログラムならば、あまり問題は無いかもしれない。
そして、デッドロックや優先順位の逆転現象やガベージコレクションが発生して、並列処理プログラムのジョブの一部が停止してしまった時、ウォッチドッグタイマーなどの処理などを使い、顧客に対して、何か問題点があったら、ウォッチドッグタイマーがシステム全体にリセットをかけてイニシャルスタートをしますから、システム運営は大丈夫ですよという話になるかもしれない。
こういう話の場合、素人は、そんな問題の有るプログラムを作ってはならないなどと言って怒るだろうが、製品の仕様では、それが許される場合がある。
ただし、それは、排他制御の問題点の解決ではなく、解消でもないが、あらかじめ、そういう事態を想定して、それでも動くシステム設計を目指せば、運用案を提案して、最小限の被害の対策がされていれば、公に許されるという事がある。
嘘を吐いて問題点が有るのに無かった事にするか、正直なコミュニケーションによって、ユーザーやシステム運用者や他のシステム開発者に相談して、最善の方策をシステム全体の開発者に対策を立ててもらって許してもらうか。
システム開発者ならば、必ずこんな問題に巡り会ったりするものだ。
その時、多少のデーターが間違っていても、ノンストップのシステムを作ってくれなる依頼をされる事があったりする。
その時、作っているメインのデーターベースの排他制御を無くしてデッドロックや優先順位の逆転現象が無い様にする代わり、メインのデーターベースの値が不定な時がありますよなる話でシステム開発する場合もあるかもしれない。
ただし、こういう問題点を述べ、許されてしまう奇特な人とは、また、次の開発担当者にさせられてしまい、親会社から仕事を与えられて、その仕事を成し遂げる事によって実力を付けてもらい、また、以前失敗した同じ仕事を与えてもらって、問題の無いシステムを作り直してもらおうなどという、回りくどいやり方で、親会社に信頼されるという人間がたまにいるものである。まぁ~、こんな人はめずらしい人である。
この場合、システム開発とは、成功談や技術力が最高機密ではなく、失敗談とその後のフォローの長いストーリーが会社経営の会社人事を含めた最高機密という事になるだろうか。
こういう人はイメージで考えて仕事をする人間ではなく、論理で考えて仕事をする人間である。ただし、この論理で考えて仕事をする人間の最大の欠点は、正直である事と技術力が無い事である。
こういう人間は、たまにいて、たとえどんな下っ端の下請けの人間だとしても、親会社が成長させて実力を付けさせてやろうという事で仕事と教育が与えられる人間である。


5.タスク間通信とトランザクションデーター。

 ジョブの流れが業務フローの形で表されるタスク構成ならば、業務を引き継ぐタスクとタスクの間には必ずデーターの受け渡しがあるものである。
このデーターの受け渡しが構造体を持ったデーターの場合、それをトランザクションデーターと呼ぶ。
トランザクションデーターは、タスク間通信する最初の段階でデーターが作られて、その後タスク間通信では、作られたデーターの先頭のメモリーのポインターを渡して、そのジョブのタスク間の通信用に使われるパターンと、ポインターでは無くそのままの構造体のデーターのままでタスク間通信のまま使われるパターンがある。
これらのタスク間通信のオブジェクトとは、たいていはセマフォによるタスク間通信と併用してFIFO構造のデーターベースによって作られたデーターキューかメールボックスが使われる。
 まずは、チケットプリンターの搬送系による例を示す。
次の様に、ジョブが1次元のタスクのセッションであり業務フロー順にトランザクションデーターが流れる構造に作られている。
〇 受信タスク→タスク1→タスク2→タスク3→データー印字タスク
受信タスクによってトランザクションデーターが作られ、そのトランザクションデーターは、チケットを搬送するタスク1、タスク2,タスク3を経由して受信タスクによって作られたトランザクションデーターの内容を印字タスクが印字する。
この様なソフトを作ると、必ず、受信タスクから得られたチケットプリンターの情報は、トランザクションデーターの流れと一致してチケットを搬送する各タスクと一致して流れそして最終的にデーター印字タスクによってデーターが印字される。
この様にトランザクションデーターの流れは、業務フロー通りに管理されながら各タスクを動かして流れてくれる。
これは、並列処理である。であるから、このトランザクションデーターによる管理方法があれば、並列処理を伴いながら、たとえ業務フローの処理を隙間無く動かしたとしてもタスク間通信として流れているトランザクションデーターの位置を管理する事で、それぞれのチケットの位置と内容の順番管理する事ができるのである。


6.ランデブ。

 ランデブには、ランデブポートという変数があり、これを中心に、ランデブ呼び出し、ランデブ受付、ランデブ返答、ランデブ回送というサービスが展開される。
イメージ的に考えれば、同じ電話番号を元に複数電話受付する事ができる電話回線と同じである。
複数のお客様を受け入れる事ができる一つの会社の電話番号がランデブポートの役割を果たす。
この会社へ電話をかけて呼び出しする側は、この会社のランデブポートにランデブ呼び出しをするというイメージになってくる。また、この会社のランデブポートには複数の受信する電話機があり、ランデブ呼び出しによって送られたデーターを受け付けている。これがランデブ受付の役割である。
つまり、ランデブ呼び出しもランデブ受付も、この会社の電話番号であるランデブポートにアクセスしてサービスを切り替えているにすぎない。
ランデブ返答とは、ランデブ受付したタスクがランデブ呼び出しのタスクに対して返答を出してランデブ呼び出しの状態を解放するためにある。
ランデブ回送とは、ランデブ受付したタスクが他のランデブポートにランデブ呼び出しするためのサービスである。
 ランデブを使うメリットとは、例えば3台あるプリンターの内、適当にどっかのプリンターへデーターを出したいという時に役に立つだろう。
プリンターへプリントを申し込む側が、ランデブ呼び出しであり、プリンター側がランデブ受付である。
この3台のプリンターの内、一つが、別の5台のプリンターに接続されていたとしたら、この場合、ランデブポートを設けランデブ回送し5つのランデブ受付のプリンターに接続されているという状態になってくる。
ランデブ返答とは、プリンター処理が終了した時、メッセージを与えながらプリンターの終了を告知するために使われるのである。
 ランデブポートの変数の構造には、ランデブ呼び出し用キューとランデブ受付用キューが最低限必用である。

並列処理概論 ver1. 著者:吉田作太郎。

並列処理概論 ver1.


はじめに
これは、OSを作るための本ではなく、マルチタスクOSを利用してプログラムを作る事を第一の目的とした本である。第二の目的は、オブジェクト指向のグループ化の性質を利用してマルチタスクで動くプログラム設計の手法を学習するための本である。
まず、マルチタスクを理解する足がかりとなったものは、セマフォーを使ったタスク間通信のサンプルを理解する事から始まった。これによってマルチタスクにおけるプログラミングとは、タスク同士の連係プレーによって成される事を理解できた。次にこのタスク間通信の部分をオブジェクト指向設計のオブジェクトにしてみた。すると、オブジェクト指向の有効な活用方法を理解する事ができた。これが、私が初めて同時にマルチタスクとオブジェクト指向を理解するきっかけとなったのであった。

前書 並列処理の概略
(メカニズムの説明と設計とその可能性について述べる)
なぜ、並列処理であるマルチタスクが必要であるか?
複数の装置が順番に一つずつ動いて一連の動作をしているとする。
シングルタスクでは、それ以上の動作をさせる事はできない。
しかし、マルチタスクを使った設計では、順番管理をしながら、一つ一つの装置が確実に順番通りに動きながら同時に複数の装置を隙間なく動かす事ができる。
それは、CPUの計算速度の高速化のためではなく、複数の装置の処理の連係プレーの1セッションの高速化のためにマルチタスクがある。
そして、それをふまえて、マルチタスクを活用した設計は、並列処理できるタスクの連携プレーのセッションの数を容易に増やして、高度な並列処理を実現させる事が可能になる。このタスクの連係プレーの実現のためには、タスクとタスクの間には、さまざまな形のタスク間通信が使われている。
私の並列処理の基本設計の設計作法は、DFDとオブジェクト指向のシーケンス図である。
それは、ハードウエアの振る舞い方も同時に記述する事が可能である。
しかも、今、これからのCPUは、マルチコアの時代に突入しようとしている。
マルチタスクの設計作法が分かれば、その基本は、マルチコアにも生かされる。
マルチタスクOSにおいて、シングルコアCPUはRUN状態が1つに対して、マルチコアCPUは、RUN状態がコアの数の分だけ持てる事が特徴である。
そして、このマルチタスクを用いたシステムの設計の基礎が分かれば、その応用は、あらゆる並列処理を記述する事が可能となる。
例えば、データー通信によるネットワークによって機能分割され分散統合されたシステム。
また、複数CPUを搭載したハードウエアのシステム。
そのシステムの構成と振る舞いを並列処理として記述する事ができるだろう。
 さて、並列処理の設計の重大な問題は、「デッドロック」である。その他にマルチタスクは、優先順位を持つため「優先順位の逆転現象」の問題を抱えている。これは、共に排他制御から生まれる問題である。
その他にも、並列処理のプロトタイプの設計についてのあり方の考察などをしている。
そして、各種問題解決型の設計のパターン化についても考察をしている。



目次
1.プロセス、ジョブ、タスク。 3
2.タスクの構成。 3
2.1.処理の流れ。 3
2.2.他のタスクへ実行権を渡すためのWAIT状態にする処理。 3
2.3.編集処理のタスクの優先順位を低くさせる意味。 4
3.ジョブの設計。 4
3.1.業務フロー型のジョブの設計のパターン。 4
3.2.オブジェクト指向型のジョブの設計のパターン。 4
4.プロセスの設計。 6
5.タスク間通信とトランザクションデーター。 7
6.ランデブ。 7
7.シングルタスクによるマルチタスクの実現方法。 8
7.1.ジョブの設計。 8
7.2.全体を動かすフロチャートの作り。 8
7.3.全体の動きについての説明。 9
8.並列処理による高速化。 9
9.マルチコアの意味。 10
10.スーパーコンピュータ。 10
11.労働について考える。 10



1.プロセス、ジョブ、タスク。

これからマルチタスクOSを用いてシステムの振る舞い方を設計する技法を説明する。
システムを仕事単位で考えてみよう。
システム全体の運動をプロセス。
プロセス内部の仕事の一連の流れをジョブ。
ジョブを細かくして仕事の一部分の作業(処理)の事をタスクと呼ぶ。
 つまり、ジョブとは、業務フローの形として表され、タスクという作業の流れ図の1セッションの集まりの事である。
ジョブが集まった全体の仕事の事をプロセスと呼ぶ。
並列処理の設計とは、コンピューターのプログラミングにおいて、この世のプロセスが全て並列的に動いている事を前提にシステム設計するという方法論である。
プロセスが並列処理なのだから、その下の概念のジョブも並列処理である事は当然であり、また、そのジョブの下の概念であるタスクも並列処理を行っている並列処理における最小単位である。


2.タスクの構成。

 並列処理におけるタスクとは、生成したプログラムは常に循環系のループとして動く構造をしている。
まず、イベントが来るまでWAIT状態として停止している。
そのタスクを動かすイベントが発生したらWAIT状態を解除してタスク内の状態遷移図に従ってその状態における処理をして、また、イベントが来るまでWAIT状態として停止する処理を再度実行するというループ構造の処理となっている。
初期処理を終えたタスクの処理の流れとは、状態遷移図に従って実行されるように設計する。

2.1.処理の流れ。

①  実際のタスクの設計の構造とは、ます、初期処理があり、そこでタスクの状態遷移図の変数と、タスクのエラー状態の変数を、ゼロに初期設定する。
② 初期処理を終えると、整数であるタスクの状態遷移図の変数の値に従って、各処理へサブルーチンコールする条件ジャンプを実行する。
③ この状態遷移図の変数の値に従った各処理へのサブルーチンコールを終了したら、その処理がエラーコードを設定したらエラー処理を実行できる様に作る。
④ もし、エラーが無ければ、「他のタスクへ実行権を渡すためのWAIT状態にする処理」を実行する。
⑤ ②へループする。
タスクの設計図によって設計されている状態遷移図の中に、「イベントが来るまでWAIT状態として停止する処理が入っている。
その処理を実行する状態遷移図の変数の値とは、ほとんどがゼロである。
この状態遷移図には必ずドキュメントとしてマトリックスを付加させる事。
さて、このタスクの状態遷移図の変数は、オブジェクト指向設計では、このタスク専用の属性として取り扱う事。すると、デバッグ時、状態遷移図の変数の値を参考にしやすいのと同時に、このタスクと、タスクに使われる状態遷移図の変数を利用しているサブルーチンも、同じオブジェクトの属性の変数として取り扱われ、プログラミング中、参照しやすくなってくる。

2.2.他のタスクへ実行権を渡すためのWAIT状態にする処理。

 本来ならばREADY状態にしても良さそうであるが、もし、自タスクの優先順位が高い場合、マルチタスクOSのディスパッチ(タスク切り替え)部分はREADY状態にした後すぐにRUN状態になってしまうので、他の優先順位の低いタスクに仕事を回す事ができなくなる。
このため、この部分はタイマーWAITさせる事によって他の優先順位の低いタスクにも仕事を回させるようにする方法が多くとられている。
しかし、優先順位なるものが存在しない簡略化したマルチタスクOS環境ならば、WAITする状態をREADY状態にさせた方が良いだろう。更にこの簡略化したマルチタスクOSならば、他の装置へデーターを送り出した後のレスポンスを確認するためのタイマーWAITする処理を作る時は、CPUに接続されているタイマーICの時間を計測してWAITする時間内ならばREADY状態にさせWAITする時間を経過した後ならばRUN状態にさせるようにしておけば良いのである。

2.3.編集処理のタスクの優先順位を低くさせる意味。

 編集処理とは他のタスクへ実行権を渡すという処理をほとんどする事ができず、しかも処理が長すぎる。
そこで、わざと優先順位を低くして他のタスクに実行権のほとんどを渡し、そして優先順位の高いタスクが処理を終えたら、自編集処理を継続的に実行してもらうための仕組みとして優先順位をわざと低く設定している。
ただし、送受信タスクとは、どの教科書にも優先順位が高い様に設計する事がセオリのようであるが、送受信タスクの中にデーターを編集する作業があるのならば、そのタスク内のこの作業に関してだけ、優先順位を低く設定した方が良いだろう。そうしないと、他のセンサーを取り扱っているタスクも停止する事となってしまうからである。
優先順位を低くする方法論とすれば、優先順位の低いランデブポートのタスクを使うか、その処理の始めは優先順位をわざと低くさせてメインの処理を実行した後は元の優先順位を元に戻すという方法論が考えられる。


3.ジョブの設計。

 ジョブの設計とは、構造化設計では、DFDによって表現される。
また、オブジェクト指向設計においては、シーケンス図かアクティビティー図が使われる。
更に、オブジェクト指向設計ならば、タスクとタスクの間に、DB(データーベース)のオブジェクトを追加してプロセスを通してデーターの流れで表現させる方法を使う。

3.1.業務フロー型のジョブの設計のパターン。

タスク1→タスク2→タスク3→タスク4

始めは、全てのタスクはWAIT状態であった。
タスク1が起動して処理を終えたら、WAIT状態であったタスク2が起動した。
起動したタスク2の処理を終えたら、WAIT状態であったタスク3が起動した。
起動したタスク3の処理を終えたら、WAIT状態であったタスク4が起動した。
タスク4の処理を終えたら全てのタスクはWAIT状態になってしまった。
こういうストーリーが考えられる。

3.2.オブジェクト指向型のジョブの設計のパターン。

タスク1→DB1→タスク2→DB2→タスク3→DB3→タスク4

始めは、全てのタスクはWAIT状態であった。
タスク1が起動して処理を終える時、DB1にデーターを書き込んでからタスク2のWAIT状態を解放して(タスク間通信する事)、タスク1が次のタスク間通信を待つためにタスク1を初期状態へ戻す。
タスク2のWAIT状態が解放され起動して処理を終える時、DB2にデーターを書き込んでからタスク3のWAIT状態を解放して(タスク間通信する事)タスク2が次のタスク間通信を待つためにタスク2を初期状態へ戻す。
タスク3のWAIT状態が解放され起動して処理を終える時、DB3にデーターを書き込んでからタスク4のWAIT状態を解放して(タスク間通信する事)タスク3が次のタスク間通信を待つためにタスク3を初期状態へ戻す。
タスク4のWAIT状態が解放され起動して処理を終える時、タスク4が次のタスク間通信を待つためにタスク4を初期状態へ戻す。

 DB1、DB2,DB3は、たいていは、トランザクションデーターを使ったタスク間通信用のデーターベースである。この様なタスク通信型データーベースは、一つのクラスとして表し、このクラスをC++の場合、new演算子を使って、それぞれDB1、DB2、DB3のインスタンスを生成してプログラムとして活用するものである。これが、オブジェクト指向設計のHAVEという性質を利用した便利な活用方法となる。
例)
Task_Tusin_Db_Class * db1 ;
db1 = new Task_Tusin_Db_Class ;
Task_Tusin_Db_Class * db2 ;
db2 = new Task_Tusin_Db_Class ;
Task_Tusin_Db_Class * db3 ;
db3 = new Task_Tusin_Db_Class ;

ここで、データーベースオブジェクトの役割について説明する。
DB1とは、タスク2をWAITさせる役目とタスク1によってタスク2のWAIT状態を解放させ起動させるという仕組みが整っている。このためDB1は、これを「タスク間通信」するオブジェクトの部品と呼ぶ。こでは、DB2、DB3も同様に、「タスク間通信」するオブジェクトの部品と呼ぶ。

 タスク間通信に使われるデーターベースオブジェクトの例を示す。
マルチタスクOSで、セマフォーを使う場合、その多くのDBはFIFOである。たまに、「FIFO+タスクの優先順位」なるものがあるかもしれないが、これは例外に近い。
マルチタスクOSで、イベントフラグを使う場合、その多くのDBはフラグ制御されたデーターベースである。

全てのタスク間通信に使われるデーターベース部分のオブジェクトは、必ず排他制御を設定する事。データーライトだけではなくデーターリード時にも排他制御をほどこす事。その最大の理由とは、1変数のリードだと問題ないと思っている人達が多いが、これが、データーアクセスのために複数の変数のリードだと途中書き込みが発生した場合、値が不定になってしまう可能性が高い。であるから、複数の数値を取り扱う場合は迷わずデーターリード時でも排他制御を使う事。
この場合、セマフォーを使うのだが、どうしてもアクセスするタスクの優先順位が違って優先順位の逆転現象が起こる場合、セマフォーをミューテックスに変更するという可能性を持つ。
もし、このミューテックスを使いたくなければ、このデーターベースにアクセスするタスクの優先順位を一定に保つための工夫が必要である。

 オブジェクト指向はグループ化する事ができる。
DB1とタスク2、DB2とタスク3、DB3とタスク4をグループ化して、それぞれ、タスク2、タスク3、タスク4と表現されると、このオブジェクト指向型のジョブの流れとは、3.1.で示した業務フロー型のジョブの設計のパターンとなるのである。


4.プロセスの設計。

 ジョブを設計して比較すると、各ジョブ内のタスクの内、同じ一つの装置を取り扱うタスクがあったりする。そして、同じ一つの装置を取り扱うのでその処理のタスクを実行するには互いに排他制御が必用である場合が多いものである。
そこで、同じ装置を取り扱うタスクをオブジェクト指向設計によってグループ化して一つのオブジェクトとすれば、そのグループ化した属性では、排他制御用のセマフォー変数を使ってグループ内のタスクの排他制御を行えば良いではないか。
この様に、排他制御とは、同一データーベースを取り扱うタスクの問題であったり、同一装置を取り扱うタスクの問題であったりする。

 ここにオブジェクト指向の概念を導入してみる。
すると、同一データーベースを取り扱う排他制御でも、同一装置を取り扱うタスクの排他制御でも、同一ならば、そこをグループ化して一つの同一オブジェクトとして取り扱いその属性には一つの排他制御の変数を設定しておけば良いという事になってくる。
こうやって、「3.2.オブジェクト指向型のジョブの設計のパターン。」の設計作法を活用して複数のジョブをながめて見れば、排他制御におけるデッドロックの発見とその回避する対策も見る事ができるようになるだろう。
また、デッドロックを発見する事ができるシミュレーターの作成も容易になってくるだろう。

さて、デッドロックの発生のメカニズムとは、たいていの本には次の様な事が書いてある。
資源Aと資源Bがありました。
1つのタスクは、資源Aを排他制御でロックした後、資源Bを排他制御でロックして、その後、資源AとBとにかかった排他制御を解放しました。
もう一つのタスクは、資源Bを排他制御でロックした後、資源Aを排他制御でロックし、その後、資源AとBとにかかった排他制御を解放しました。
この時、資源AとBは、とある事象によってロックがかかる事象が発生します。
それをデッドロックと申します。
ざっと、こんな具合の話があるものだ。
私は疑問に思った、資源Aを使うためにロックしたのならば使った後に資源Aをアンロックすれば良い。そして、次に資源Bを使う時も資源Bのためにロックしたのならば使った後に資源Bをアンロックすれば良い。
これで、デッドロックは避けられると考えた。
しかし、事態はそうじゃなかったらしい。
2つの排他制御をするためにロックして使わなければならない資源があるとしたら、順番がA→Bならば、他の順番もA→Bでなければデッドロックを回避できない。もし、逆の事があるとしたらデッドロックが発生する。
こう述べたいのだろう。

 では、こういうオブジェクト指向型のジョブの設計のパターンがあるとする。
タスク間通信用のデーターベースには必ず排他制御があるものとして、DBとして表現する。
タスク1→DB_X→タスク2→DB2→タスク3→DB_Y→タスク4
タスク5→DB_Y→タスク6→DB2→タスク7→DB_X→タスク8
この時は、DB_XとDB_Yは、デッドロックする可能性が高いです。
特にジョブの中のタスクが隙間無く流れていれば、デッドロックになる可能性が高い。
もし、デッドロックをなくすとすれば、
タスク5→DB_X→タスク6→DB2→タスク7→DB_X→タスク8
というように、排他制御のある部分の順番を整理しなおして設計し直さなければならなくなってくる。

これが、プロセスの設計の肝心な所である。
今回は、排他制御のあるDBについて説明したが、これは、複数のタスクを排他制御によって制御している同一オブジェクトにも言える事である。
そして、ここには、排他制御によるデッドロックの問題以外に、タスク同士の優先順位の逆転現象まで、プロセスの設計には考慮しておく必用があるのである。


5.タスク間通信とトランザクションデーター。

 ジョブの流れが業務フローの形で表されるタスク構成ならば、業務を引き継ぐタスクとタスクの間には必ずデーターの受け渡しがあるものである。
このデーターの受け渡しが構造体を持ったデーターの場合、それをトランザクションデーターと呼ぶ。
トランザクションデーターは、タスク間通信する最初の段階でデーターが作られて、その後タスク間通信では、作られたデーターの先頭のメモリーのポインターを渡して、そのジョブのタスク間の通信用に使われるパターンと、ポインターでは無くそのままの構造体のデーターのままでタスク間通信のまま使われるパターンがある。
これらのタスク間通信のオブジェクトとは、たいていはセマフォーによるタスク間通信と併用してFIFO構造のデーターベースを使用しているものである。
 まずは、チケットプリンターの搬送系による例を示す。
次の様に、ジョブが1次元のタスクのセッションであり業務フロー順にトランザクションデーターが流れる構造に作られている。
〇 受信タスク→タスク1→タスク2→タスク3→データー印字タスク
受信タスクによってトランザクションデーターが作られ、そのトランザクションデーターは、タスク1、タスク2,タスク3を経由して受信タスクによって作られたトランザクションデーターの内容を印字タスクが印字する。
この様なソフトを作ると、必ず、受信タスクから得られたチケットプリンターの情報は、トランザクションデーターの流れと一致して各タスクを流れそして最終的にデーター印字タスクによってデーターが印字される。
このトランザクションデーターは、指定された情報を業務フローで管理しながら各タスクを動かしてくれる。
これは、並列処理である。であるから、このトランザクションデーターによる管理方法があれば、並列処理を伴いながら、たとえ業務フローの処理を隙間無く動かしたとしても順番管理する事ができるのである。


6.ランデブ。

 ランデブには、ランデブポートという変数があり、これを中心に、ランデブ呼び出し、ランデブ受付、ランデブ返答、ランデブ回送というサービスが展開される。
イメージ的に考えれば、同じ電話番号を元に複数電話受付する事ができる電話回線と同じである。
複数のお客様を受け入れる事ができる一つの会社の電話番号がランデブポートの役割を果たす。
この会社へ電話をかけて呼び出しする側は、この会社のランデブポートにランデブ呼び出しをするというイメージになってくる。また、この会社のランデブポートには複数の受信する電話機があり、ランデブ呼び出しによって送られたデーターを受け付けている。これがランデブ受付の役割である。
つまり、ランデブ呼び出しもランデブ受付も、この会社の電話番号であるランデブポートにアクセスしてサービスを切り替えているにすぎない。
ランデブ返答とは、ランデブ受付したタスクがランデブ呼び出しのタスクに対して返答を出してランデブ呼び出しの状態を解放するためにある。
ランデブ回送とは、ランデブ受付したタスクが他のランデブポートにランデブ呼び出しするためのサービスである。
 ランデブを使うメリットとは、例えば3台あるプリンターの内、適当にどっかのプリンターへデーターを出したいという時に役に立つだろう。
プリンターへプリントを申し込む側が、ランデブ呼び出しであり、プリンター側がランデブ受付である。
この3台のプリンターの内、一つが、別の5台のプリンターに接続されていたとしたら、この場合、ランデブポートを設けランデブ回送し5つのランデブ受付のプリンターに接続されているという状態になってくる。
ランデブ返答とは、プリンター処理が終了した時、メッセージを与えながらプリンターの終了を告知するために使われるのである。
 ランデブポートの変数の構造には、ランデブ呼び出し用キューとランデブ受付用キューが最低限必用である。


7.シングルタスクによるマルチタスクの実現方法。

 プログラムに大きなループを作って、各タスクにはタスク間通信用のタスクスイッチを配備するという構造になってくる。
まずは、ジョブ内部の処理の流れを次の様にする。

7.1.ジョブの設計。

タスク起動処理→タスクA→タスクB→タスクC

7.2.全体を動かすフロチャートの作り。

① 初期処理A。タスクAのタスクスイッチをOFF、状態遷移図の変数とエラー状態の変数をゼロに設定。
② 初期処理B。タスクBのタスクスイッチをOFF、状態遷移図の変数とエラー状態の変数をゼロに設定。
③ 初期処理C。タスクCのタスクスイッチをOFF、状態遷移図の変数とエラー状態の変数をゼロに設定。

④ タスク起動処理。

⑤ タスクAのタスクスイッチがOFFならば、⑨へ行く。
⑥ 整数であるタスクの状態遷移図の変数の値に従って、タスクA内にある各処理へサブルーチンコールする条件ジャンプを実行する。
⑦ この状態遷移図の変数の値に従った各処理へのサブルーチンコールを終了したら、その処理がエラーコードを設定したらエラー処理を実行できる様に作る。
⑧ もしエラーが無ければ次の処理を実行。

⑨ タスクBのタスクスイッチがOFFならば、⑬へ行く。
⑩ 整数であるタスクの状態遷移図の変数の値に従って、タスクB内にある各処理へサブルーチンコールする条件ジャンプを実行する。
⑪ この状態遷移図の変数の値に従った各処理へのサブルーチンコールを終了したら、その処理がエラーコードを設定したらエラー処理を実行できる様に作る。
⑫ もしエラーが無ければ次の処理を実行。

⑬ タスクCのタスクスイッチがOFFならば、⑰へ行く。
⑭ 整数であるタスクの状態遷移図の変数の値に従って、タスクC内にある各処理へサブルーチンコールする条件ジャンプを実行する。
⑮ この状態遷移図の変数の値に従った各処理へのサブルーチンコールを終了したら、その処理がエラーコードを設定したらエラー処理を実行できる様に作る。
⑯ もしエラーが無ければ次の処理を実行。
⑰ ④へ行く。

7.3.全体の動きについての説明。

タスク起動処理によってタスクAのタスクスイッチをONにする。
するとタスクAが動き出す。
ここで、タスクAが次の処理を起動させたかったらタスクAはタスクBのタスクスイッチをONにしてからタスクAの状態遷移図の変数をゼロにして初期設定しながらタスクAのタスクスイッチをOFFにする。
するとタスクBが動き出す。
ここで、タスクBが次の処理を起動させたかったらタスクBはタスクCのタスクスイッチをONにしてからタスクBの状態遷移図の変数をゼロにして初期設定しながらタスクBのタスクスイッチをOFFにする。
するとタスクCが動き出す。
ここで、タスクCが次の処理を終了させたかったら、タスクCの状態遷移図の変数をゼロにして初期設定しながらタスクCのタスクスイッチをOFFにする。
シングルタスクにおいて、この様にタスクスイッチがタスク間通信の役割を果たす。


8.並列処理による高速化。

 今、とある処理にかかる時間が、均一に1回という時間がかかるとする。
10の処理を100回する場合、シングルタスクの場合、10*100=1千回の時間がかかる。
これを、並列処理によって10の処理を並列的に並べて100回実行させる事ができれば、100回の時間がかかって終了する。
これを、並列処理によって10の処理を直列に接続させる事ができれば、100+9の時間がかかって終了する事になる。
これをCPUに例えて言うならば、パイプライン処理、または、バケツリレー方式、ベルトコンベア方式による高速化と呼べるだろう。
これは、ジョブの高速化である。
ジョブをタスクに分けてベルトコンベア方式によって流すと理論上最高速度に達するには分割したタスク分高速化が図れるという事になるのである。
 さて、この事から、プロトタイプのジョブの設計では、並列処理を全て数珠つなぎにした1次元のタスクの流れにした方が、並列処理の高速化をある程度含めて間違い率の少ないプログラム開発をする事ができる。
そして、このプロトタイプの設計が成功したら、今度は、並列化した方が高速化が図れる場所を並列化して設計し直す事で、本当の並列処理を生かした完璧なプログラムを作るというプログラム開発する作戦が考えられる。


9.マルチコアの意味。

 一般のマルチタスクとは、シングルCPUによって全てのタスクを動かすものであり、それは、一人の人間によって全てのジョブをこなすというものである。
マルチコアによるマルチタスク処理とは、複数のCPUによって全てのタスクを動かす者であり、それは、複数の人間によって全てのジョブをこなすものである。


10.スーパーコンピュータ。

 多くの場合、3次元データーの高速化であり、シミュレーションに使われる。
気象データーであったり、流体力学に基づいた計算であったりする。
3次元データーの一つのセルを1タスクとして、各タスクがタスク間通信によって立体的に結ばれ、それが、マルチコアによって並列計算されているという構造である。更に、このマルチコアのCPUが、3次元上に立体的に配置されており隣り合ったCPUに対してCPU間通信をして、巨大な3次元空間の演算をしていると考えられる。

参考:
題名:杉本大一郎 著、手作りスーパーコンピュータへの挑戦 テラ・フロップス・マシンを目指して、講談社ブルーバックス


11.労働について考える。

 あらゆる労働とは、並列処理である。であるから、業務フローを書いて順番に実行されるべきものである。
また、この業務フローが完成していれば、他の人を雇って並列的に仕事をさせて、人数を投入させた分、仕事を効率的にこなしてゆくのに役立つ。
すると、仕事の管理監督する側も、この業務フロー通りに仕事をこなしているかどうかによって、仕事の成果を計測しながら数値化して計測する事ができる様になるのである。

通信プロトコルの基礎。その4/4。著者:吉田作太郎

14.ポーリングと人間関係。

 ポーリング電文とは、相手から情報を引き出す電文である。
取り出す情報とは、相手の状態把握と相手からのメッセージである。
人とのコミュニケーションとは、相手から言ってくれる事を待つだけではなく、挨拶をし、こちらから聞き出す事もできなければならない。
そうすれば、通信処理においてリカバリーができる様に、相手の持っている問題点や障害を聞き出し、スムーズに物事が解決する仕組みを作る事ができる・・かもしれない。
 人間関係に使われる簡単なポーリングとは、例えば、自分の発する言葉や態度から、レスポンスとして発してくる相手の言葉や態度の情報を受け取って、どんな感情を持って何を考えているのかとか、嘘をついているのかなどを、ある程度、把握するためにある。
この様なポーリングのあるコミュニケーションとは、いろいろ応用すると、周りの人間関係を観察する事によって、誰がどの様な感情をいだき何を考えているのかという情報を把握できて、インテリジェンスの有る対応をする事ができる様になるものである。
この様に、ポーリングは、一つの手段ではあるが、機械でも障害対策ができたのと同様に、人間関係にもいろいろと役に立つ事ができるものである。

 さて、一般のコミュニケーションにおいて、ポーリングとは何だろう?
代表的なのは、挨拶である。
「ポーリング=挨拶」
ポーリングの無いコミュニケーションほど、一方通行の単調なデーター通信であり、高度なコミュニケーションをする事ができない。
また、インテリジェンスの無いコミュニケーションしかできない。
 こういう事だからこそ、挨拶の無いコミュニケーションとは低級である。
挨拶があり、うなずきなどの態度がある、ポーリングを活かしたコミュニケーションとは、人間関係を豊かにし高度にしてゆくものだと、私は機械の立場で考えるのである。

15.通信プロトコルを作る時の苦労。

通信プロトコルを作ってデバッグしている時、多くの失敗をして悩むものである。
正常終了の時はうまくゆくプロトコルだが、電文異常の時、不可解な動作をする通信プロトコルを作ったりするものである。
仕様に、「異常電文が来たらNAKをレスポンスとして返す。」という条件を元にプロトコルを作ると、ほとんどの人は、異常電文の時、必ず、一つの異常電文の入力に関して、一つのNAKのレスポンスを返すのではなくその異常電文の文字数分のNAKのレスポンスを返すので、多くのNAKのレスポンスを受け入れて、多くの受け取ったNAKの数の分の正常電文を出そうとする失敗した仕様を作ってしまうものである。
この時、多くの試行錯誤をして、いかに正しいプロトコルを作るかが、課題となる。
 また、通信プロトコルとは、デバッグの段階ではうまくゆくのだが、論理的には異常となる部分を抱えたプロトコルを作ったりする事があったりする。
私も、そういうプロトコルを作った経験がある。
こういう時、周りの者達は、「実験段階では正常に動いているのだから、あまり気にかけるな。」と言われたりするが、やはり、論理的に考えられて起こる障害は、実務においては必ず起こるものである。
だから、責任の持てるプロトコル作りと、それを実現するためのプログラム作りとは難しいものだ。
私の犯した障害は、「送信権の確保の仕様」が未熟な通信プロトコルを実務に運用させた事である。
この障害はデバッグ時には発生しないものだが、実務での運用面では、必ずその障害は発生しているらしい。(あくまでも空想によるシミュレーションだが)

私は、その障害に対する対策でいろいろ悩んでいたが、他の会社(富士通機電)の仕事で通信プロトコルの仕事をする機会を与えられた。
そして、私は、その障害に対する解決方法を知った。
それは、教科書にも載っているポーリングという通信においての基本の技術が最善の策なのであった。
また、私は、その会社の仕事をして、リカバリーの自動化の仕様も学んだ。
また、トランスペアレントな通信の技法も学んだ。
まともに動く通信プロトコルを作るのには、私一人の力だけではどうにもする事ができなかったが、通信プロトコルの事を知っている会社の仕事を与えてもらって、その仕様から多くの事を学ぶ事で、やっと、実用面でも論理面でもまともに動く通信プロトコルのヒントを多く知る事ができるようになったのだ。
これで、私は、ほとんどの自分の悩みが消えたが、その他にも研究する分野があって、それぞれ解決していった。
ここに書いてあるのは、私の実務と研究においての成果である。
私は、ここに、私が考える最善の通信プロトコルを記述した。

その他、通信プロトコルに関してのプログラム開発において、自分で通信プロトコルを作ったら、その部分というのは自分自身が良く把握しているだろうから問題が無いが、その部分が誰か別の人間が作ったアプリケーションからの流用であるならば、こういう部分は、どの様になっているのだろうかという質問をする必要があり、質問を受けた方も相手を納得させるコミュニケーションが必要であろう。
そして、その開発者と、そのアプリケーションを流用する人間との間に、コミュニケーションの断絶があるとしたら、例えば、以前そのアプリケーションを開発した人間が転職しただとか、どっかの部署に行ってコミュニケーションする事ができないという事態が発生していたら、ちょいと、そのプログラムを流用するプロジェクトは停止した方が良いであろう。
その理由は、いくらその部分に関してのドキュメントがあったとしても、そのドキュメントに対して解説してくれるコミュニケーションに関しての断絶があれば、まともなプログラムを作る事ができないし、責任を持って仕事をする事ができないからである。
いい加減な仕事しかできない環境ならば、いくら仕事の依頼が来たとしても、仕事の依頼を受けない方が良いと私は思う。

16.昔のBASICでの通信割り込みの問題。

 昔のパソコンに搭載されていたN88BASICを含めた多くのBASICには、RS-232Cの仕様の部分で同じ欠点を持っていた。
BASICには、RS-232Cの通信の割り込み処理を記述する事ができるのだが、ここに大きな問題点があった。
割り込みが発生するのは、文字データーが一文字入ると発生するのではなく、RS-232Cの一文字データーのフレームの最初にある受信パルスを得ると割り込みが発生するのであった。
だから、受信割り込みが発生しても、一文字も入る事が無く、一文字データーのフレームの最後のパルスを受け取ってからやっと一文字の受信データーを受信する事ができ、そのため受信割り込みが発生してから一文字分のデーターのフレームまの最後が来るまで待つためのソフトウエア・ループによる遅延を使って、RS-232Cの受信割り込みの処理を作らねばならなかった。
だから、RS-232Cの通信速度が遅いと、割り込みする時点から一文字が入ってくる時間が多くかかり、その分、ソフトウエア・ループを長くしないと、まともな受信データーを受け取る事ができなかった。

これが、BASICのRS-232C通信の受信に関する大きな問題点であり、この解決策は、RS-232Cの受信割り込み処理を活用するのではなく、RS-232Cのデーターの受信データー数をチェックするBASICの命令を活用して、その命令で受信データーがあるかどうかを絶えずポーリングする事により、受信データーの受信の有無を確認して、そして、データーがあれば、受信処理を実行する様な仕組みに設計すれば、受信割り込みに使うソフトウエア・ループを活用せずに、しっかりと漏れが無く受信データーを受け取る事ができる様になるのである。

こういう対処方法は、あらゆる本を読んでも書いていなく、BASICのサンプルプログラム通りに作っても、通信エラーがあるとデーターを受信する命令で無限に止まってしまう仕様であり使い物にはならないサンプルプログラムであり、だから人づてにどうやれば良いかと聞くと、「ソフトウエア・ループを活用すると良いよ。」などと言われるものであるが、どれも、本質的な解決策とはなっていなかった。
オンラインの仕事とは、特に通信プロトコルに関する低レベルのメカニカルな部分とは、自分で実験して、やってみて、自分で解決策を考えなければ、まともに動いてくれない事が多々あるものである。
コンピューターの仕事とは、理論だけではだめな事が多くあり、機械の都合やソフトウエアの仕様の問題があって、やってみなければ、きちっとした製品が作れないという事が多いものなのである。

 やってみなければ分からない事とは、昔の8ビットCPUのZ80でも言える。
データーバス、アドレスバスの線がZ80から出ているのだが、このバスの線は、プルアップ抵抗を付けないとまともに動く事ができないのだ。
まるで、オープンコレクターかオープンドレインの様な感じに取り扱わなければならないのだが、これを知らないで、データーバス、アドレスバスを作り、RAMやROM,または、周辺装置に接続しても、ちっとも動いてくれないものだ。
また、ロジックアナライザーを使っても、全く問題の原因を追及する事ができないものだ。
設計時点で上手くゆくと思って回路設計やソフトウエア設計をしても、実装時、動かない事は良くある事で、単体テストをして動く事を確認できても接続テストになると、なぜか動かないだとか、動く時もあるだとか、動かない時があるという事が良く発生するものである。
だから、ソフトウエアの仕事とは、ハードウェアの障害を見つけてデバッグを助けたりする事も仕事の内であったりもする。
または、ハードの障害があれば、ソフトウエアによって、ある程度の修正をして、障害を解決する事も多々ある。

 この様に、コンピューター関連の仕事とは、最初に設計する理論だけでは動かないという事が多いハプニングの連続である。
だから、設計や単体テストの時点で、デスマーチがあるなどと言っているプロジェクトとは、すでにそのプロジェクト自体問題があると言えるだろう。
未知の装置を使い、未知のソフトウエアを使い、設計しても上手く動いてくれない事が多くあり、その困難な部分を見つけ出し、皆でその問題を解決してゆかねばならない事がコンピューター関連の仕事に多いのである。
また、この様な仕事とは、多くの人数を雇ったから解決できるという類の問題ではない。
コンピューター会社が、何人月の仕事ですからなどと数値化する事もできない仕事であるし、何人月かけたからその仕事を成し遂げる事ができるという仕事でもない。
つまり、見積もりで数値化させる事が困難な仕事である事が多いのである。
そういう仕事を成功させるには、問題発見能力とそれをレポートにして誰か優秀な人間(特に優秀な企業からのお客さん)とコミュニケーションする能力と原因追及能力と問題解決能力が無ければ、成し遂げる事ができない仕事である。

その様な事であるから、ソフトウエアの制作とは、ステップ数で計算して予算の見積もりを立てるだけでは済まない事が多くあり、また、設計計画を立ててマイルストーンを設けてプロジェクトを成功に導かせるという方法論も通用しない事も多くある。
もし、その様な事でプロジェクトが成功するのであれば、それが、どんなに大きなプロジェクトであろうとも、恵まれた環境で成し得たたいした事の無い仕事だと言えるだろう。

17.データー通信とアプリケーション。

 私は、次の様なオンライン処理を担当した事がある。
X25という通信プロトコルを持った装置のバージョンアップの開発である。
その開発をする以前では、私は、通信プロトコルにおいて肝要な仕様とは次の通りだと思っていた。
○ リトライシーケンス(電文を送信して、レスポンスがエラー時、または、レスポンスが返ってこなくてタイムオーバーしたら、電文を再送する仕様)とそのエラー対策。
○ ポーリングによる相手の状態の監視。
リカバリー処理。

そこで、私は、X25が、データーを送信して送信エラーが返ってきた時、どの様な仕様になっているかが分からなかった。
その装置では、それは無視する事であった。
もし、エラーが発生したら、特別に相手の装置の状態監視する仕様も、リカバリーするための仕様も無く、ただ無視して、送りっぱなしにしておくという仕様であった。
それによって、データーを送信するタスクを作りやすくしていたのだった。
では、どの様にして、相手の装置を監視するかというと、ヘルスチェックという方法のみであった。
このヘルスチェックによって、相手の装置が故障したかを監視し、リカバリー処理が必要かを判断したりするものであった。
これは、私の常識から逸脱した仕様であった。
データーを送信して、相手の装置がエラーだったら、普通、エラー処理をするものだというのが私の常識であったからだ。
だから、データー送信に関してエラー処理を無視するはずが無いと思い込んでいた。
 この様な仕様だと、電文を送信する側の局は、障害を見つける事はできない。
電文を受信する側の局は、相手側の局から送られる通常の電文とヘルスチェックの電文が来なかった時の時間を計測して、ある一定の時間、電文がやって来なかったら、タイムアウトと判断して、未接続、または、相手の局に障害が発生したのだと判断する事ができる。
ここに、電文を送受信する線が二種類あって、その片方の線が使えなくなっていたら、電文を送信する側の局が使えない場合エラーをタイムアウトのエラーを確認できないが、電文を受信する側の局が使えない場合タイムアウトのエラーを確認する事ができる。
これは、ある意味、相手の局が存在するかどうかを判断する場合、中途半端な仕様であると言えるだろう。

また、X25プロトコルには、一つの電文を送る場合、そのレスポンスエラーが発生した場合、同じ電文を二つ送ってしまう可能性も高くなるはずである。
この様な仕様だと、データーの値を+1加算する電文を送った場合、エラーのリトライシーケンスで、+2のデーターを送るという可能性を持つ様になる。
ならば、そういう通信プロトコルによって起こる障害は、私が独自に研究した内容を加えた仕様で運用せねばならない。
即ち、その問題点の解決策は二通り有り、
一つは、電文を送る場合、本電文を送った後、データーを確定する電文を送る事。
一つは、電文にシーケンス番号を付けて、同一の電文がやって来たら同一の前の電文の情報を無視して最新の電文を受け取り、次のシーケンス番号が来たら、前に受け取った電文を確定して受信データーとして取り扱う事である。これは、また、シーケンス番号エラーという事象も考慮せねばならなくなり、かなり仕様は複雑になる可能性を持つ。

その他、仕事の成功に関して、技術上の問題以外に、契約上の問題、組織運営上の問題、技術者としてのモラルの問題などが以下の様にあった。
○ 派遣契約の仕事ではなく、前任者が開発したソフトを改造してバージョンアップする請負契約の仕事であるが、この装置のソフトウエアを最初に開発した人がいなく、この装置を開発するための知識を引き継いでいる人がいないが、ただ単にやたらプログラム開発する人材を寄せ集めただけであり、仕事の作法や用語の統一ができていなく、また、そういう事もしようとしない結果、規律も統率もとれていなく、仕事の意味についても理解する事ができなく、ただ担当技術者はドキュメント整理という与えられた作業を機械的にこなす事しかできないプロジェクトである事。
○ 仕事元の質問を受け付ける窓口担当の人では、私の質問に対してそういう簡単な事は聞かないでくれと言われている。
○ この装置を開発した人では無いのに、何でも「知っている」、「分かっている」と言い張る人間がリーダーとなっている。
○ 上司命令で、勝手に仕事元が要求もしない仕事をプロジェクト全体の仕事としてやる事になったが、その仕事の料金を仕事元に請求して拒絶させられた事。
○ 我々のプロジェクトがお客さんのパーティーに招待されたら、リーダーがそのパーティーの壇上でプロジェクトの挨拶をする時、お客さんの悪口を平気で、いや、憤った声で言って、そして挨拶が終わってもどってきたら自分の仲間達に「やってやったぜ」などと息巻いている。
私が辞職させられる事がだいたい決定したあたりに、仕事元は、同じ部屋で、他の会社に同じ仕事を依頼して仕事をやらせている事。

この様に、ここにプログラム開発において困った人というのがいた。
私は、このリーダーから、「X25という通信プロトコルで開発しているという話しですが、X25での通信エラーが発生した場合、どんな仕様で対策する事になっているのですか?」と聞いたら、でっかいバインダーに入っているX25通信プロトコルを持ち出してきて、「これにX25に関する仕様が全て入っているから、調べろ。」と言うだけであった。
まぁ~、そのバインダーに入っている書類は確かにその装置内においてX25通信プロトコルの仕様を実現している仕様書ではあるが、それは、X25を取り扱う部分だけの仕様書であり、通信エラーを出したら、アプリケーションではどう対応するかまでは載ってはいない書類であった。
それで、「知っている」、「分かっている」、「ここに載っている」、「全て書いている」、「読み方が足りないだけだ」なる事を言ってこちらに的外れな仕様書を与えて仕事について指導し、私の質問に対して無視しようとしているのだから、私も訳が分からないで困ったものだった。
というよりも、それどころか、私にとって、全然分からない仕事であり、責任をとれる様な仕事とはならないものであり、ただ、仕事の責任者から言われた通りの事しかやるしかなかった仕事であった。
という事で、私は、この仕事を請け負っている会社から仕事の実務能力が無いという事で、プロジェクトの途中で辞職させられた。
ただ、今、思うと、私が辞職させられた理由とは、私には問題発見能力が高く、見つけた問題点をレポートで書いて報告する仕事のスタイルを持っていたが、プロジェクトのリーダーは、問題が無かった事にしておこうとする人間だったので、プロジェクトとして邪魔な人間だと思われたので退職させられたのであろう。

 さて、このプロジェクトは、失敗したと噂で聞く。
そして、私を辞職させた会社は、営業上、いろいろと制裁を加えられているらしい。
ろくに仕事の事を知らないのに、また、知らないのに知ったかぶりしながらお客さんとコミュニケーションして、「虐げられてきた。虐げられてきた。」と周りの人達に言いまわったりする異常なリーダーのいるプロジェクトであった。
この様に、なにやらやたら威勢が良くてプライドの高い下手な知ったかぶりをする人間の事を仕事にとっても役に立つ人間だと信じて責任者としたプロジェクトや会社というものは、大損害をするものである。
会社の信用を低下させるだけではなく、あるいは会社を倒産させるぐらいの事だってやりかねない事だってあるものだ。
だから、当然、当人の人生は狂ってしまうものではあるが、その他にも、他の多くの人間を巻き込んでその人達の人生を大きく狂わせる事があったりするのである。

 こういう事であるから、会社って、ただ技術力のある人間だけを望んではいけない。
モラルのある人間であるかどうか。
そういう事が、本当は大事なのである。
仕事が出来なかったら、レベルの低い仕事を引き受けて担当するという勇気だって必要である。
できない仕事であったのならば、正直に自分の実力を示して、それでも仕事をやれと言われたら、「どうか、いろいろとご指導お願いできないでしょうか。」と仕事を与える上司やお客さんに頼んだ上で、仕事を引き受ける事だって必要なのである。
それを、出来ない仕事に対して、正直に自分の実力を示しても、強制的に強引に屈服させて「やれ。」と言い、「どうしたら良いでしょうか」と聞くと「自分で考えろ。俺は人を使う立場の人間だから、その様な事に対応してはいけないんだ。」と言う人間がいたとしたら、その仕事をやる人間が失敗しても文句を言ってもしょうがいないし、責任を追及してもしょうがないものなのだ。
むしろ、無理な仕事を無理だと分かっていても、強制的に強引に屈服させて「やれ」と言った人間の方に責任があると言えるだろう。
それなのに、世の中の人間のほとんどという者は、強制的に強引に屈服させて「やれ」と言った人間には責任が無く、あくまでも強制的に強引に屈服を受けて仕事を引き受けた担当者の方に責任があり、そいつが一番の悪だと思って処罰してしまう人間というのが、かなり多いものなのである。
そんな事は間違いなのに。

だから、そんな間違いをする事無しに仕事をする事とは、仕事をやらせる人間にも、仕事を引き受ける人間の方も、モラルが必要であるが、人を使う側の人間とは、「何がモラルなのか?」という問いに対して答えられる哲学を持たなければならないのである。
そういう哲学無しに、人に仕事を任せても、ろくな仕事をさせる事はできないであろうし、また、他人(お客さんや仕事を担当する者達や仕事関係者)の人生を破滅させ、自分自身の人生も破滅させ、会社の存続までおかしくしてしまう事になってしまうのは、当然なのである。

 人を使う者とは、会社の雰囲気や空気を読んで仕事をするなどというのは、許されないと思った方が良いであろう。
そんなあいまいなものにのまれている様では、まともな善悪の判断をして仕事の舵取りをする事はできない。
だから、経営というものは、人を使う事というものとは、ある程度の事は、絶対的な善悪を判断して行動するための哲学というものを必要とするのである。

通信プロトコルの基礎。その3/4。著者:吉田作太郎

10.ネットワーク通信の有用性。

 一般のコンピューター通信とは、1対1の通信である。
RS232Cとか、USB端子は、1対1の通信しかできない。
この点、LANだと、次の事ができる。
○ 一つの装置の一つの回線で、複数の装置をコントロールする事が可能。
○ 一つの装置の一つの回線で、複数の装置からの仕事の依頼を受け付ける事が可能。
この2点の特徴を生かして、システム作りができる。
ちなみに、インターネット回線だと、世界中のコンピューターとアクセスできるという特徴があり、この利点を生かして、コンピューター通信をする事が可能である。


11.パケット通信に関して。

世界中にインターネットによるデーター通信の通信網が設置されている。
このデーター通信の通信網の装置の仕様を簡略化するためにパケットを使う事となっている。
長すぎる通信電文は、インターネットの接続網に接続できない。
ここで、データーを送信する装置は長すぎる電文を区切って、パケットとして分解してインターネットの送信網に送り、データーを受信する装置は、このパケットを組み立て直して、元の電文を作り上げて、長い電文をインターネットの送受信網を介して送受信するために、インターネットはパケット通信を採用している。
 なぜ、データー通信には、パケットが使われるか?
パケット通信網の間にある中継局のバッファーの余裕を与えるためである。
長さが不特定な通信電文ならば、その電文を中継する中継局には収まらないぐらいの大きなメモリーを使わなければならない。
場合により、通信電文長の長さによるエラーが発生する可能性が高い。
そのために、長い電文を伝送路に使わせないために、長い電文を短いパケットに区切って活用するためにパケット通信する事を考え出された。
 このパケットは、インターネット網だけではなく、LAN網においても有効である。
例えば、LAN同士を接続するスイッチングハブやルーターなどの機器にも有効である。

11.1.パケット通信によるデジタル通信の中継局に関しての考察。

○ 通信電文をパケット化して、そのパケットをまた同じ通信電文に組み立てる仕様が必要。(中継局以外の送信局、受信局)
○ 通信品質の向上のためにパケット一つ一つに対してエラーチェックして、もし、エラーが発見されれば、パケットの送り先に同じパケットを再送してもらう様にする仕様が必要。(中継局以外の送信局、受信局)
○ パケット・エラーによるリトライシーケンスは、エラー発生時(タイムアウトとデーターエラー)、再送してもらうが、再送してもらう回数の限度を設ける事。
○ パケット・エラー発生時、もし、パケットを再送する回数が限度を超えてしまうというエラーが発生した場合、そのパケットは無視する事。無視して無くなったパケットは、受信局が通信電文を組み立てる時のチェックで、通信電文をパケット化した装置から再送要求を出す。それでも、エラーであり続けるのならば、その通信電文を無視する事。
○ 通信伝送路の障害で、「無視されて伝送漏れのあるパケットデーター」と「正常なパケットなのにエラーと判断されて出来た複数の同じパケットデーター」のパケット障害の尻ぬぐいをするのは、データーの送り元と受信先のプロトコルによって対応する事。
○ パケットには、通信電文をパケット化しているデーターと、通信電文の送り元と送り先のアドレス情報、それに、エラーチェックのためのデーターが最低限必要。
○ これらの処理を実現するためには、マルチタスクOSが欠かせない。
○ データー通信の中継局は、マルチタスクでなければ処理をする事は不可能である。受信した各パケットに関して一つずつパケットデーターのエンティティーを持ち、それを中継局が他の中継局へ再送する時、パケットデーターの中身がきちっと送信できたかをレスポンスによって確認し、正常であれば、パケットデーターのエンティティーを削除して使えない様にする。また、エラーによるリトライシーケンスの回数が多すぎる場合、パケットデーターのエンティティーを削除して使えない様にする。
以上の様な仕様が必要であろう。
 要は、エラーがあれば、リトライシーケンスを繰り返してエラー復旧を図るが、それでもダメな場合は、無視する事によって、ノンストップのデジタル通信の中継局を実現させる事が大事である。
 次にデジタル通信の中継局は、マルチタスクでなければならない。
パケットデーターを受信したら、いったんキューにため込んで、一つずつパケットを取り出して、データー分析して正常ならば、そのパケットデーターを送り出す。
これによって、パケットデーターは、伝送路に関して隙間無くデーターを送る事が可能となる。
それには、マルチタスクでなければ、対応できない。
もし、シングルタスクでやろうとすれば、パケットデーターは、伝送路に関して隙間無くデーターを送る事はできないので、伝送路の有効活用はできないため、伝送速度はいちじるしく低下する。
 次に輻輳(ふくそう)対策について考える。
パケット通信によるデジタル通信の中継局が、あまり、通信データーが多すぎてパンクしそうになる状態を輻輳と呼ぶ。
こういう時は、中継局に望まれるのはノンストップである事である。
そのためには、伝送データーを間引きする事で、デジタル通信の中継局がノンストップである事を持続し続けていなければならない。
この時、デジタル通信の中継局に「無視されて伝送漏れのあるパケットデーター」と「正常なパケットなのにエラーと判断されて出来た複数の同じパケットデーター」が存在する事となる。
中継局の仕様とは、こんなもので、完璧に通信データーの品質保証をする事はできない。
だから、最終的にデーターの面倒を見る装置は中継局の両端にあるデーターを送受信している装置であり、それが、最終的に全てのデーター通信の尻ぬぐいをする事となる。
 問題点。
○ パケットの順番、データーの順番が、
  順番通りに伝送されない事がある。
 利点。
○ データーを一度、メモリーにためて送受信するので、
  デジタル通信網での通信速度が違っても対応できる。

11.2.OSIとTCP/IP。

 OSIに関する本を読んでみたが、分らなかった。
どんな目的があってOSIの7つの階層があるのかは全然分からなかった。
このプロトコルは、リカバリー処理もないしシステムとしてやってゆけるのだろうかという疑問を持った。
だから、勝手に自分流の考えで推測したOSIの事を考えTCP/IPの事を考えた。
すると、OSIもTCP/IPも、リカバリー処理を考慮していない通信プロトコルである事がはっきりした。
更に、ポーリング電文による相手の局の存在確認や状態確認するという仕様は規定されていないのである。
リカバリーする処理、ポーリングの活用による各種のサービスする処理は、この通信プロトコルを利用して別途、独自に作ってゆかねばならない処理なのである。
以下は、その結論を考慮した上でののOSIとTCP/IPについての考察である。

OSIの7つの階層。

アプリケーション層 :不明。
プレゼンテーション層:不明。
セッション層  :今まで記述してきたRS232Cの
         通信プロトコルが担当できる部分。
トランスポート層:電文とパケットの変換に関する仕様を担当。
ネットワーク層 :パケットのネットワークの接続ルーティングに
         関する仕様を担当。
データーリンク層:物理層同士間のパケット通信の
         プロトコルに関する仕様を担当。
物理層     :通信するハードウェアに関する仕様を担当。

 まず、TCP/IPは、物理層からセッション層までしかなく、このセッション層が、すでにアプリケーション層となっていると推測する。
アプリケーション層の切り替えは、トランスポート層に番号があって、その番号に従って、それぞれのアプリケーションに対して、トランザクション・データーの送受信ができる様になっているのではなどと推測する。
 では、OSIのアプリケーション層、プレゼンテーション層、セッション層とは何か?
まずは、プレゼンテーション層を中心にして考える事が妥当であろう。
電文を送信する場合のプレゼンテーション層の役目とは、それぞれのアプリケーションから出るトランザクション・データーを結合させてまとめて電文としてセッション層に送る。電文を受信する場合のプレゼンテーション層の役目とは、セッション層から受け取った電文をトランスポート層がそれぞれのアプリケーションに対して分配する。
このパケットで生成された電文からそれぞれのアプリケーションを動かすトランザクション・データーまでのデーターの入出力のコントロールするために、この3つの層があるのではないかと推測する。
つまり、TCP/IPとOSIの通信プロトコルの思想は、この部分が大きく違っているのだと考える。
ただし、トランスポート層とネットワーク層とデーターリンク層と物理層に関しては、TCP/IPもOSIも共通の意味によって取り扱う事ができると推測する。
それは、送信する場合は1つの電文から複数のパケットを作るという仕様と、受信する場合は複数のパケットから1つの電文を作り出すという仕様を満足させる事である。

 ここでは、セッション層と物理層の説明は無視しておく。
セッション層とは、トランザクション・データーという電文を取り扱うものだという事にしておいて、何も検討をしない事にしておこう。
物理層とは、通信に使われるハードウェアの仕様と考えておいて、無視して何も考えないでおく事にしておこう。

 次に、ネットワーク層とデーターリンク層に関して。
TCP/IPにおけるネットワーク層とは、IPに関わる部分であり、ここで、インターネットのネットワークを管理しているとの事である。
また、データーリンク層において、特にパソコンで使われているイーサーネットの役割は、物理層で指定されたMACアドレスによりLAN内の各装置にアドレス指定してパケット通信ができる様になっている。
ここに、インターネットのネットワーク用とLAN用のネットワークの識別方法があり、二重にネットワークが識別されている仕組みがあって重複している様だ。
しかし、なぜか、この二重化されたネットワークに、それぞれ別の使い方があるらしい。
例えば、ハブやブリッジは、物理層とデーターリンク層のLANのみを管理するが、ネットワーク層のIPアドレスの識別をする事は無い。
だが、ルーターは、ネットワークをIPアドレスで識別管理でき、それと同時に物理層とMACアドレスで管理されているデーターリンク層のLANもしっかり管理できる様になっているのである。

 ここで、二重になっているネットワークを接続し管理する装置について説明する。
リーピーター:物理層同士の接続する装置。
ブリッジ:外部のデーターリンク層を制御して
     LAN同士を接続する装置。
       外部のデーターリンク層を制御し、
       自物理層を管理する。
ハブ  :LAN内のデーターリンク層同士を制御して
     LANを作り上げる装置。
       外部のデーターリンク層を制御し、
       自物理層を管理する。
ルーター:外部のネットワーク層を制御して
     LANとLANを分離する。
       自データーリンク層を管理し
       自物理層を管理する。

次に、トランスポート層とは、送信の時は電文からパケットを作り、受信の時はやって来たパケットを組み合わせて電文にもどす事を目的とする。
また、それと同時に、1つの物理層に対していくつもの送受信チャンネルを論理的に作り出す事が可能な仕組みを目指して作られ、そのため一つの物理層に対して多くの局と同時送受信可能となり、マルチタスクの各タスクが一つの物理層からそれぞれの局と同時通信可能になる様に作られている。

次は、TCP/IPについて。
TCPとは、トランスポート層のプロトコルであり、IPとは、ネットワーク層のプロトコルである。
IPとは、インターネット用のアドレスにTCPで作られたパケットがアクセスする仕様。
ここで、TCP/IPを使って、セッション層から通信プロトコルを見ると、物理層では一本しかない接続が、多くの他の局の回線と物理的に接続されて並列的に送受信する事ができる様になっており、マルチタスクにおける各タスクが同時にこのTCP/IPを使用する事ができる様になっている。
このTCP/IPによって、マルチタスクの複数のタスクと他のネットワークの局との多対多の接続が可能になっているのである。
TCP/IPを使う場合、シングルタスクには意味は無い。
マルチタスクを有効に活用する通信のために有るのである。
しかしだ。
仕様をかなり限定して、シングルタスクのみで動く1チャネルで動くシングルなアプリケーション上で動かすだけの開発ならば、開発の難易度を考えると、シングルタスクのOS上でTCP/IPを開発する事ができ、最低限のネットワーク装置がある小規模なソフトウエア開発として、大いに意味あるTCP/IPのソフトウエアができるかもしれない。
 ここで、オンライン・アプリケーション開発に関して言えば、データーリンク層のMACアドレスとネットワーク層のアドレスを考慮して、セッション層では、各アプリケーションによっての通信プロトコルを決定して設計してゆく事が肝要である。

11.2.1.セッション層の工夫。
 今までの通信電文の送受信は、セッション層のプロトコルと規定しておけば、あらゆるネットワークと接続できるプロトコルが作られる事となると考えられる。
その場合、データー送信が、成功したかどうかなる問題を、データーリンク層、ネットワーク層、トランスポート層の情報を見て判断して、新たに通信プロトコルを作るのではなく、セッション層の通信プロトコルを、今まで述べてきた全二重に対応する通信プロトコルをそのまま流用して活用すれば良いだろう。
 さて、ここで、トランスポート層とは、パケットの順番管理をしてきた層であるが、短い電文の場合、トランスポート層での電文の順番管理は役に立たない場合が考えられそうである。
理由は、ネットワークにおいて電文を送る順番が前後して、正しい順番の命令(トランザクション・データー)を送れなくなくなる可能性が出てくるからである。
そういう場合、電文の順番管理をセッション層で面倒を見る仕様を作った方が良いと思う。
また、セッション層で作る電文が短いものなのならば、トランスポート層は、セッション層で作った電文をそのままパケットにしてしまうのもアイデアの一つであると考える。

11.2.2.送信権の確保の工夫。(全4重通信の構想)
 送信権の確保のためにはポーリングなどの技術を活用してきた。
今までのRS232C型のポーリングのあるプロトコルを活用すると、一つのポートを利用して送信権の確保する仕組みを持たせてセッション層で電文を送受信する事ができる。
しかし、TCPの活用を考えれば、いくつものポートを活用する事ができるので、特にポーリングの技術によって送信権の確保をせずとも、送信用に2つのポートを確保し、受信用に2つのポートを確保し、電文の送受信に関してリトライシーケンスのあるプロトコルを作る事が可能である。
ただし、ポーリングする仕様は、接続チェックしてリカバリーの仕様を満足するためには使われ続けなければならないだろう。
すると、通信で使われてきた、「送受信タスク」は、役割分担して「送信タスク」、「受信タスク」として、それぞれ全二重通信してリトライシーケンスの仕様と、接続チェックしてリカバリーできる仕様を満足させる事が可能となるだろう。
つまり、「全二重通信×2=全4重通信」という通信スタイルも考えられるという事である。

11.2.3.マルチタスクとパケット。
 一台のコンピューターのネットワークに接続する部分は一つだけである。
その中身とは、ネットワークにデーターを受信する部分と送信する部分である。
そして、この二つの部分だけで、コンピューターは内部に複数あるプログラムからそれぞれの通信処理をこなさなければならない。
この仕様を満たすためには、マルチタスクを使いこなさなければならない。

 ネットワークからデーターを受信する側は、受信したデーターを各タスクにタスク間通信を経て分配せねばならない。
それは、受信したデーターの各ヘッダーに使われているネットワークアドレスによって判断して各タスクにタスク間通信を経て分配するのである。
もし、どのタスクにも使われていないネットワークアドレスの電文であるならば、無視する事となるだろう。
ネットワークへデーターを送信する側は、各タスクからの送信するデーターをタスク間通信を経て集めたデーターを順番に送らなければならない。
このデーターは、各タスクからタスク間通信によってデーターを受け取り、そのデーターをネットワークへデーターを送信するタスクへのタスク間通信のキューに接続して、そのキューから受け取ったデーターをそのままデーター送信処理によって送信すれば良いであろう。
この時、送信するデーターは、送信する電文のデーターだけではなく、受信したデーターに対するレスポンス(「ACK」、「NAK」などの制御文字)も含まれる事となる。
その上で、データーを送受信する各タスクは、データー通信プロトコルを持って、データーの送受信の仕組みを作る事ができていなければならない。

 もし、簡略化したTCP/IPの通信プロトコルを備えたソフトを作るとするならば、TCPは、1パケットの範囲内での通信で簡略化して、データーリンク層の部分をしっかり設計して通信を行えば、組み込み系の範囲内ならば、充分実用化になる設計をする事ができる様になるだろう。

シングルタスクでも、TCP/IPを作る事が可能かもしれないが、データー送受信以外にも、コンピューターのプログラムを動かさなければならない時は、どうしても、マルチタスクを使用せねばならないだろう。
 特に並列処理を実現しているマルチタスクにおいて、パケット通信は相性が合う。
シングルタスクのデーター通信は1チャネルしか通信できない。
しかし、ここでマルチタスクによるデーター通信を取り入れると、コンピューターの一つの物理チャネルに仮想的なマルチ(複数)チャネルのデーター通信が取り扱えるので、マルチタスク上で同時並行に動作している各アプリケーションに同時データー通信を実現させる事ができるのである。

11.2.4.TCPとUDP。
 OSIのトランスポート層に関して、
送信する時、電文をパケットに分けて出力し、
受信する時、パケットを電文にまとめて入力するのが、TCPというトランスポート層のプログラムである。
このTCPというトランスポート層でパケットを作らないで電文をそのまま送受信するプログラムの事をUDPと呼ぶらしい。
ここで、TCPを使わず、UDPにて電文を送受信するUDP/IPのプログラムを使う場合、TCP/IP同様に今まで解説してきた通信プロトコルの基礎は役に立つと思う。

11.2.5.データーリンク層によるネットワーク通信。
 データーリンク層には、MACアドレスなるものがあるから、これだけでもネットワーク通信が可能である。
ただし、インターネットのネットワークは使えないのが難点である。
インターネットを使わないで、ハブなどを使って自ネットワーク内ならば、データーリンク層内だけの通信は可能だと言えるであろう。
ただし、パケット通信よりも長いトランザクション・データーの通信電文には不向きである。
パケットぐらいの長さの短い通信電文で自ネットワーク内の通信ならば有望な通信であろう。(推測)

11.2.6.コミュニケーションとは記憶を共有する事だ。
さて、余談として、ここで、このトランスポート層のTCPのプログラムのメカニズムを空想してみる。(本当は、トランスポート層もTCPもほとんど知らないから、イマジネーションで単純化したモデルを空想し、シミュレーションしてみる。)
送信する側はトランザクション・データーを分割してパケットデーターとして送信したら、受信する側のトランスポート層のプログラムは、いちいち受信したパケットデーターが到着した事を送信する側のトランスポート層にレスポンスとして知らせる。
そして、送信する側は、送信した全てのパケットデーターのレスポンスを受け取ったら、送信する側は終了電文のデーターを受信側に送る。
終了電文のデーターを受け取る受信側は、今まで受け取ったパケットデーターを組み立てて送信する側が送ったのと同じトランザクション・データーを組み立てて、正常ならば送信する側に正常終了のレスポンスを送り、異常ならば異常終了のレスポンスを送信する側に送る。
正常終了のレスポンスを受け取った送信する側は、トランスポート層の上位の層のプログラムに送信が正常終了した事を知らせパケットの送信を終了する。
異常終了のレスポンスを受け取った送信する側は、再度、新たにトランザクション・データーの全てのパケットデーターと終了電文のデーターを送るが、それでも異常終了のレスポンスを受け取ったら、トランスポート層の上位の層のプログラムに送信が異常終了した事を知らせパケットデーターの送信を終了する。
また、送信する側は、パケットデーターや終了電文のデーターのレスポンスがタイムアウトになるまで返って来なかったら同じデーターを送り直すが(リトライシーケンス)、何回か送り直してもレスポンスが返って来なかったら、トランスポート層の上位の層のプログラムに送信がタイムアウトで異常終了した事を知らせパケットデーターの送信を終了する。
さて、これは、空想の通信プロトコルではあるが、この様なデーターを送受信する動きとは、特にリトライシーケンスがあるデーター通信とは、受信する側と送信する側は記憶を共有する様に設計するという感覚になる。
私は、コンピューターにおける通信プロトコルにおいて、この様な設計思想を持っているので、コンピューター同士の機械のコミュニケーションとは、記憶を共有する事という感覚で設計している。
ここから、私は、全てのコミュニケーションとは記憶を共有する事ではないだろうかという思想を持っている。
この思想のため、私は、もし記憶を共有するコミュニケーションをする事ができなかったら、コミュニケーションに失敗したという感覚を持つ事になるのである。

11.3.ネットワーク通信のデバッグ環境。

 インターネットにおけるデバッグ環境は、LAN同士のデバッグでは不完全である。
完璧なデバッグ環境とは、2台のルーターを使って、そのルーターの両端に、インターネットによるデバッグ環境を作れば良い。
更に考えるのならば、2つのインターネット回線を契約して、その間で、インターネットによる通信をすれば良いだろう。
それが、実際の環境でのデバッグ環境となるのである。
これは、LAN同士のネットワークのデバッグ環境よりも、これは、金がかかると思う。




12.オンライン処理の基本的な通信エラー対策に関して。

 まずは、基本的な通信プロトコルとは、ポーリングという仕様は入っていないし、エラー復旧時にデーターをリカバリーするなどという仕様は入っていない。
これは、通信プロトコルに期待するのではなく、その通信プロトコルを利用するオンライン処理が担当する仕様なのである

12.1.ノンストップのシステムを作る事。

 オンライン処理で必要な仕様とは、リトライシーケンスとリカバリー処理が無ければならない。
問題点があると自動的にリトライシーケンスが発生し、そのリトライシーケンスによってデーターが壊れない様にする様にデーター設計やシステムを設計する事。
リトライシーケンスしても復旧しないとすれば、その装置は故障したとみなしてリトライシーケンスを停止させ、次は故障した装置をポーリングなどによって常に監視し、その装置が復旧した事をポーリングなどによって監視できたのならば、手動によるのではなく、自動で復旧させるシステムを作る事。
まずは、これが、ノンストップのシステムを作る事の基本である。
装置の二重化などの方法によってノンストップシステムが作られているという話を聞く。
では、どの様に二重化して、自動的に故障した装置を切り離して、安全な装置に切り替えてノンストップのシステムを作ってゆくかという設計をする時、リトライシーケンスの自動化と自動復旧のための自動リカバリーの仕様だけは基本的な仕様だと心得ておく事。

12.2.エラー対策。

 通信障害が発生した事は、通信プロトコルにおいて発見する事ができるだろう。
データーを送信した時、レスポンスが返って来なかった場合、次の事が考えられる。
○ 伝送路エラー1.(伝送路にノイズが侵入して通信エラーになった)
○ 伝送路エラー2.(伝送路が切断された)
○ 通信装置の故障。
伝送路にノイズが侵入して通信エラーになった場合は、リトライシーケンス(同じ電文を再送する事)によって通信電文が復旧する事が考えられる。
しかし、伝送路が切断されていたり、通信装置が故障したりしていては、どんなにリトライシーケンスを繰り返した所で、障害がなおる事は無い。
この場合、通信障害がある事から、装置からエラーメッセージを出す事や、警告のためのサイレンなどを鳴らす事によって、その装置を使っている人達に知らせねばならない。
 この以上を検知するには、次の方法が考えられる。

○ 二つの装置間では、一定時間は、必ず、通信をしていなければならない。もし、送るべき通信内容が無い場合、空の内容の通信電文を送る事を義務付けなければならない。
○ データーを受信する装置は、一定期間以上データーを受信できない場合は、通信エラーがあるとみなして、エラー警報を出す事。
○ データーを送信する装置は、データーを送信した時に返ってくるレスポンスが来ない時、何度か、リトライシーケンスを繰り返し、それでも正常なレスポンスが返って来なかった場合、通信エラーがあったとみなし、エラー警報を出す事。
この様な障害の復旧には、次の様な事が考えられる。
○ 伝送路をチェックして切断されていないか、伝送路の中に入っている装置が故障もしくは電源が切断されていないか。
装置の電源が切れていないか、装置が、異常状態になっていないか、その異常状態はその装置をリセットする事で回復できないか、もしくは、その装置を取り換える事によって復旧しなければならないか。

 さて、リカバリー機能の付いていないオンライン処理だと、通信プロトコルでリトライシーケンスエラーが発生した後、どの様な仕様でシステムを作れば良いか分からないでいる事になり、エラーメッセージを出してユーザーに障害対策をしてもらうという操作説明書しか書けない製品しか作れなくなるだろう。
それは、もし、通信エラーという障害が発生した時、その商品を設計した人しか対応する事ができない、ユーザーが対処する事が難しい難解な製品しか開発する事ができないだろう。
ここで、オート・リカバリーの機能を取り付けた装置だと、「従属局」の障害は、「主局」のリカバリー処理で、電源を入れなおした時に、このオート・リカバリー機能で全て解決できるという仕様が書ける様になる。(通信回線の接続を確認して断線かどうかを判断する必要があるが)
すると、ユーザー自身にも使いやすいシステムを作る事ができる。
 システムの仕様を作る上で、コンピューター上のトラブルがあったら、電源を入れなおせば全て問題解決できるという仕様が書けるSEは、障害対策の時のオペレーションの仕様がすっきり簡単となり、それが操作説明書を書く事にも生かされて簡潔になり、誰もが使いやすいシステムを作る事ができる様になるだろう。
 特に、ここで私が強調して言いたい事とは、オンラインシステムの仕様を決定して作る上で、リトライシーケンスとオート・リカバリー処理は、必須の仕様である事を思いとどめて欲しい。

通信プロトコルの基礎。その2/4。著者:吉田作太郎

4.ポーリング電文を活用する技術。

 今まで、送信する側と受信する側とに別れてプロトコルを決めてきた。
今度は、受信する側の装置もデーターを送信できる仕組みを組み立てる。
今度は、どちら側も電文を送信する事ができるので、今までの送信する側の装置の事を「主局」、受信する側の装置の事を「従属局」と呼んで、そのプロトコルを説明する。
これは、私流の一対一(ポイント・トゥー・ポイント)のプロトコルの仕様である。
その他に、今まで、リトライ処理でも修復する事ができない通信のその後の処理については説明していなかった。
そういう時は、「主局」がポーリング電文を受信側に送って、「従属局」から送られてきた電文のレスポンスから「従属局」の状態監視を「主局」がして、その障害の程度に応じてリトライ処理を繰り返す処理に加えてリカバリー処理を追加した方が良い。
リカバリー処理とは、「従属局」の装置の電文内容をリセットして「従属局」に与えるべき全てのデーターを最新のものに更新する処理である。
 さて、こういう事を可能にするには、いろいろなプロトコルが存在するだろうが、私がこれを勧める理由は、誰が作っても容易に実用的で安定な通信の仕様を満たす事ができると考えるからである。
この仕様によって、誰もが、必要最低限の仕様を満たしながら商品として成り立つ通信プロトコルの設計ができるための参考資料として記述する。

利用目的1.従属局の送信権を確保。
 今まで主局が電文を送信して従属局がレスポンスを出す仕組みであった。
これでは、従属局から電文を送信する仕組みが無い。
その仕組みを可能とするには、主局から従属局へ電文を引き出すための電文を送り、従属局はレスポンスの代わりに主局への送信電文を送り出せば良い。
この主局から従属局へ電文を引き出すための電文の事をポーリング電文と呼ぶ。
従属局から出る電文は、「ACK」,「NAK」のコードではない。
「STX」と「ETX」で囲われ電文の終わりにエラーチェックコードを付加したトランザクション・データーである。
この電文の良い所は、主局側が、従属局から電文の送信のタイミングを作る仕組みになっているので、主局側の処理の仕組みが作りやすくなり、半二重の通信でも運用可能である事である。

利用目的2.従属局の状態の把握。
 一つは、空の電文としてポーリング電文を活用する。
何回か送ってレスポンスが無ければ従属局との接続が未接続であると判断する。
未接続の理由は、電源が入っていない。故障している。接続が切断されているという理由が考えられる。
 もう一つは、従属局の状態把握のためである。
従属局側から送り出すメッセージのカテゴリーはいくつかある。
(1) 従属局の内部状態。
○ 電源入れたての状態。
○ 主局から内部状態をクリアーされた状態。
○ 主局からイニシャル電文を受け取ってイニシャライズを受けた状態。
○ リカバリーを受けた状態。
○ 通常電文受け入れ可能状態。
(2) 主局側から受け取った電文のシーケンスナンバー。
(3) 主局からの電文のシーケンスナンバーのエラーの有無。
(4) 従属局から送信する電文の有無。
(5) 従属局の通信エラー状態1。
    ○ ポーリング電文「ACK」。
    ○ ポーリング電文「NAK」。
(6) 長時間の通信切断の確認。
(7) その他の従属局からのメッセージ。
これらの情報が入っているトランザクション・データーを「STX」と「ETX」で囲いエラーチェックコードを付加して電文とする。

これら2つの利用目的のレスポンスがあると、従属局のレスポンスはすでにメッセージを伝えるトランザクション・データーの領域に入ってくる。

4.1.主局からの電文の再構成。
 主局から従属局に送る電文を次の通りにする。
(1) リセット電文。(C)
(2) イニシャル電文。(I)
(3) データー電文。(D)
(4) データー引き出し電文(ポーリングの一種)。(Q)
(5) 状態監視電文(ポーリングの一種)。(P)
(6) リカバリー電文。(R)
 主局が電源入れたての時、従属局にリセット電文を送り、次にイニシャル電文を送る。
リセット電文は、従属局の記憶をクリアーするための電文である。
イニシャル電文は、従属局にイニシャルデーターを送るための電文である。
イニシャル完了後はデーター通信は通常状態として取り扱う。
通常状態は、主局は従属局にいつでもデーター電文を送る事ができる。
主局が従属局に送る電文が無い場合、状態監視電文を送り続け、接続状態を監視続けながら従属局側から送りたい電文があるかどうかを確かめる。もし、従属局側から送りたい電文があったとすると、データー引き出し電文を送って従属局のメッセージを引き出しなかが受け取る。
 さて、通信プロトコルにおいてリトライシーケンスが発生して接続不能におちいった場合、主局は状態監視電文(P)を従属局に送り続け従属局側のレスポンスを待つ。
そして、主局側のコンピューターは、接続不能のメッセージをディスプレーに表示したり警告音を出したりする。(ディスプレーに表示するメッセージの例は、「接続しているケーブルが断線しているか、接続しているコンピューターが動かなくなっている状態です。ケーブルが外れているか確かめ、また、それでも動かない場合、接続しているコンピューターの電源を入れ直して下さい。」という内容になるだろう。)
もし、レスポンスが返ってきて、そのレスポンスで通信続行可能である事が判明した場合、主局は通常状態として通信を続行する。
しかし、通信続行不可能の場合や従属局が電源を入れなおされてリセットされた状態だと判断すると、従属局にリセット電文を送り、イニシャル電文を送り、次に今まで記憶していなければならないデーター電文の蓄積の全てをリカバリー電文として送りデーターのバックアップをする。
バックアップ完了後、従属局との通信状態を通常状態にし、従属局側は、いつでもデーター電文、状態監視電文、データー引き出し電文を受け入れ可能にしてゆく。
○ 主局の電源入れたての時の電文の流れ。
   C→I→(D,Q,P)
○ 通信接続不能状態の時。
主局のディスプレーに接続不能のメッセージを表示。
オペレーターに接続確認をうながし、従属局側の装置の確認後リセットや電源入れ直し、装置の入れ替えしたのち電源入れ直しなどをしてもらう。
主局は、従属局にポーリング(状態監視電文を送る事)し、従属局からのメッセージを待つ。もし、ポーリングに対するレスポンスを受けたら、接続可能状態になったと認識して、再度、電文を受けられる状態になるか、それとも、主局が従属局のデーターのバックアップをして通常状態にもってゆくかを判断してゆく。
※ これは、これでも、最低限の仕様として記述しているのであって、不通時の仕様で相手の装置に停止命令や通信エラーによる表示停止状態にしメッセージを出させるなどの仕様を追加せねばならない事もありうる事に注意する事。
○ 従属局側が通信接続不能状態から解放され主局のデーターのバックアプを受ける時の電文の流れ。
   C→I→R→(D,Q,P)

4.2.主局からの電文のフォーマット。
○ 「STX」(1バイト)
○ ヘッダー部。(固定長)
電文種類。(1バイト)・・・・・(C,I,D,Q,P,R)
主局側シーケンス番号。(2バイト)・・(00~99)
従属局からの引き出し電文のシーケンス番号。(2バイト)・・(00~99)
電文の長さ(3バイト)・・・・・(000~999)
予備(スペース、4バイト)
○ データー部。(可変長:0~MAXバイト)
○ 「ETX」(1バイト)

4.3.従属局からのレスポンス用電文フォーマット。
○ 「STX」
○ 主局へのレスポンス。(1バイト)
(ACK・・0、NAK・・1、シーケンス番号エラー・・2)
○ 主局から受け取ったシーケンス番号。(2バイト)(00~99)
○ 主局から受け取った電文種類。(1バイト)(C,I,D,R)
○ 従属局(自)の電文の有無。(1バイト)(無・・0、有・・1)
○ 従属局(自)の引き出し電文(Q)用のシーケンス番号。(2バイト)
       (スペース2バイト、01~99)
○ 従属局(自)内部のエラーメッセージ。(4バイト)(任意)
○ 予備。(3バイト)(とりあえずスペースでうめる。)
○ Q電文用、引き出し電文メッセージ(可変長)(0~最大(MAX))
○ 「ETX」
以下、従属局からのレスポンス用電文フォーマットの説明をする。

4.3.1.従属局が送り出す、主局から受け取ったシーケンス番号について。
○ 電源入れたての時のシーケンス番号は、2バイトのスペースとして内部保管する。
○ シーケンス番号の初期値設定は、リセット電文(C)を受信時、数値チェックした後、無条件で内部保管して設定する。
○ ポーリング電文(Q,P)以外の電文は、シーケンス番号をチェックする。シーケンス番号は、内部で保管している番号と同じか、1つ上の場合正常として再度保管し設定する。それ以外は、シーケンス番号エラーとして主局へのレスポンスにエラーコードを設定する。なお、シーケンス番号が99の場合、次に番号は01とする。
○ ポーリング電文(Q,P)を受け取った時は、以前主局から受け取って保管したシーケンス番号を採用して設定する。電源を入れたての時、ポーリング電文を受け取ったら、2バイトのスペースを設定して返す。

4.3.2.従属局が送り出す、主局から受け取った電文種類について。
○ 電源入れたての時の電文種類は、1バイトのスペースとして内部保管する。
○ ポーリング電文(Q,P)以外の電文で、主局からのレスポンスが、ACKの場合、主局から受け取った電文種類を設定し、それを内部保管する。(C,I,D,R)
○ ポーリング電文(Q,P)以外の電文で、主局からのレスポンスが、ACK以外の場合(NAK,シーケンス番号エラー)、内部に保管されている電文種類を設定する。(C,I,D,R,スペース)
○ ポーリング電文(Q,P)を受け取り時は、以前主局から受け取った電文種類を採用して設定する。電源入れたての時、ポーリング電文を受け取ったらスペースを返す。

4.3.3.従属局が送り出す、内部エラーメッセージについて。
 プロトコルの製作者がカテゴリーを作って主局に対して伝えるべきメッセージが送れる様にする事。
特に思いつかない場合、予備としてスペースにしてもかまわない。

4.4.Q電文のプロトコル。
(1)  主局から送る電文でQ電文以外では、従属局からの引き出し電文のシーケンス番号は、2バイトのスペースである。
(2)  従属局からのレスポンスで、従属局から主局へ送りたい電文がある事を確認した時、主局は、Q電文を送る。
(3)  主局が最初にQ電文を送る時、最初の引き出し電文シーケンス番号は、“01”に設定する。すると、従属局から、“01”番目の電文メッセージがやってくる。
もし、主局側の電文受信にタイムアウトが発生したり、正しい電文がやってこなかったりするとリトライシーケンスで、同じ引き出し電文シーケンス番号で、従属局に電文要求する。
このリトライシーケンスが、設定してある限度(だいたい目安として3回ぐらい)を超えると、従属局側に障害が発生したと主局が判断し、通信接続不能状態と判断して、一定間隔で従属局にポーリング電文(P)を送って状態監視を行なう。
 さて、01の電文が正常に受け取れたら、次は、02の電文、03の電文と、従属局からの電文の有無を確認しながら電文を受け入れようとする。
そして、主局からのQ電文から引き出される電文で従属局からの電文が無いと確認できたら(従属局の電文の有無が0に設定され、Q電文用引き出し電文メッセージが無い状態の時)、Q電文による従属局からのメッセージの受け取りのセッションを終了する。
 このセッション間は、引き出し電文シーケンス番号が“01”の時と同様に、主局側の電文受信にタイムアウトが発生したり、正しい電文がやってこなかったりするとリトライシーケンスが発生し、リトライシーケンスが設定してある限度を超えると、従属局側に障害が発生したと主局が判断し、通信接続不能状態と判断して、一定間隔で従属局にポーリング電文(P)を送って状態監視を行なう。
(4)  従属局側のための引き出し電文シーケンス番号は、“99”を上限(MAX)とする。だから、1セッション内では、99電文以内でなければならない。

4.5.P電文の活用。
 主局が、従属局に送る電文が無ければ、主局は、従属局の状態監視のために、絶えず一定間隔にP電文を従属局に送らなければならない。
これによって、従属局からの電文の有無と、接続状態、状態監視を絶えず続けるのである。
 従属局側は、主局からの電文が、ポーリング電文を含めて全ての電文が、なかなかやってこないかどうかを判断する。
つまり、電文がやってくる時間を測定し、その時間がタイムアウトになったら、従属局は、接続不能状態と判断してエラーメッセージや警告を出す様にする仕様を加える事。(主局側も断線などによって接続不能状態を検知したらエラーメッセージや警告を出す様な仕様を加える事)
 なお、従属局の電文受信のタイムアウトの仕様は、全てのプロトコルのデバッグを終了した後に、仕様を追加してプログラム設計し、デバッグをする事。
理由は、全てのプロトコルを製作中にこの仕様を加えると、各プロトコルのデバッグがやりづらいからである。
だから、プロトコル設計は、デバッグのためにも、スケールアップする感覚で、一つ一つの仕様を確かめながら完成させなければならない。
そうしないで、始めから全ての仕様を満たして設計すると、必ず失敗するので注意が必要である。

4.6.レスポンスの間引き。
 さて、シーケンス番号で管理されたポーリングのある電文は、レスポンスの間引き運転が可能であろう。
それは、従属局のエラーは、いちいちレスポンスで知るのではなく、ポーリング電文を出した時点で主局が管理しておいてもかまわないのではという考えである。
このため、主局が送る電文は、従属局のレスポンスを待つ事無しに、高速に送れる事となる。
ここまで、通信プロトコルの設計に関してスケールアップしてきたのだから、省略できる所は、省略してもかまわない部分も出てくると思って考え直す事も大事である。

4.7.リセット電文の必要性。
 イニシャル電文以外に、通常の電文であるトランザクション・データーによってその機器がコントロールしているそれぞれの機器や機能に対して、オールクリアーや、パーシャルクリアーするデーターの仕様も考えてトランザクション・データーの運用を考えておく事。

4.8.その他。(ヘルスチェック)
 ポーリング電文の使い方の基本は以上の通りである。
ここで、その他の機器間の接続チェックする通信プロトコルには、ヘルスチェックというのがある。
一対一の接続において、主局が送る電文が無い場合、一定時間が経ったら空の電文を送り、また、従属局の方も主局に送る電文が無い場合、主局に空の電文を送る。
これをヘルスチェックと呼ぶ。
このヘルスチェックとは、送る電文が無い時、互いに空の電文を送るのである。
これは、ポーリング電文と同様に、互いに接続チェックするためと状態監視するためにヘルスチェックするのである。
ヘルスチェックの電文は、空ではあるが、ポーリング電文同様に、イニシャル状態かなどと相手に自分の状態を知らせるとい約束事を作ってその空の電文にその約束事を満たすデーターを乗せなければならない。
すると、そのデーターから相手の状態を判断する事によって、リカバリーなどのサービスを互いに与える仕組みを持つ仕様を考えておかねばならない。
また、ヘルスチェックにおいて、互いに一定時間、接続不可の時があればタイムアウトが発生したとみなし、それは接続している相手が断線したか装置が故障したと判断して、エラーメッセージや警告を出したりしり相手の状態監視と復旧のためのサービスを行ったりする仕組みを通信プロトコルに定義しておかねばならない。
 なお、このヘルスチェックの仕様は、全てのプロトコルのデバッグを終了した後に、仕様を追加してプログラム設計し、デバッグを行う事。
理由は、全てのプロトコルを製作中にこの仕様を加えると、各プロトコルのデバッグがやりづらいからである。
 さて、このヘルスチェックの問題点だが、ポーリングは、シングルタスクをループさせただけのマルチタスクの処理で実現できるが、このヘルスチェックは、リアルタイムマルチタスクでなければ実現できないだろうと思う点である。
また、ヘルスチェックとは全二重通信でしか成立しないが、ポーリングは全二重通信も半二重通信の両方に対応できる特徴がある。
このため、私は、ポーリングのある通信プロトコルの方が高い有用性を持つと考えている。

4.9.クライアント・サーバー。
 ポーリングを出す側のコンピューターの事をクライアントと呼び、ポーリングを受ける側のコンピューターの事をサーバーと呼ぶ。(という事になりそうだ)



5.親局と複数の子局のある電文形式。(マルチポイントの電文)

(1)構成。
親局一つに、複数の独立のアドレスを持った子局が一回線の通信バスに接続されている。
ここでは、ブロードキャスト(全局通信)、ユニキャスト(一対一通信)は可能であるが、マルチキャスト(一対多通信)は対応できない。
┌───┐ 
│親 局│ 
└─┬─┘ 
  ┌─────┬──┴──┬──────────┐
┌─┴─┐ ┌─┴─┐ ┌─┴─┐      ┌─┴─┐
│00 │ │01 │ │02 │ ・・・・ │ N │
│子 局│ │子 局│ │子 局│      │子 局│
└───┘ └───┘ └───┘      └───┘
(2)仕様。
○ 親局は、電文を全子局に送信できる。(送信電文のアドレスを全局に指定すれば)
○ 親局は、各アドレスの付いたそれぞれの子局に電文を送る事ができる。
○ 親局は、各アドレスの付いたそれぞれの子局から電文を受け取る事ができる。
○ 親局は、それぞれの子局の接続状態、電源入れたてなのかという状態監視ができる。(ポーリングにより)そして、障害があった子局の装置は、障害の回復をしたらすみやかに親局からリカバリーされて通常業務に移行できる様なプロトコルを定める事。
○ 親局の送信電文に対して、子局はレスポンスを出してはいけない。その代わり、親局側は、絶えず各アドレスの付いた子局に一回ずつポーリング電文を出し接続確認と状態監視している。
(3)電文フォーマットについて。
今まで、一対一の電文送受信のフォーマットに対して次の項目を追加する。
○ 親局側は、送信する子局のアドレス(2バイト)(00~98、99ならば全局指定)を追加。
○ 子局側は、互いに重複しない自アドレス(2バイト)(00~98)を追加。

 さて、この接続形態で半二重通信の場合、子局同士で通信できる仕様を追加する事が可能である。(追加可能な仕様)
それは、親局が子局に対してポーリングして別の子局に送信したがっている場合、ポーリングされた子局から別の子局へ通信する仕組みを作る事である。
そのためには、送受信の電文のフォーマットを多少変更しなければならないが、ここでは、その仕様とフォーマットは記述しない。(理由:長くなるから。)

6.トランスペアレントでない電文の送受信+ENQコードについて。

トランスペアレントな電文で無い場合、制御コードと通信電文内容のキャラクターとは違う。
そこで、ACK,NAKなるレスポンスは、電文内容と混在されても区別する事ができる。つまり、二つの局は、互いにデーターを送ってそのレスポンスを確かめるという技を使っても、混同する事も無いし、混乱する事も無い。
つまり、主局側の装置にとってポーリングする事すら必要無さそうである。
 さて、実際、プログラムを作ってみると、電文を送受信する二つの装置間において、どちらか一方に、送信権というタイミングを確保するための通信プロトコル仕組みがあった方が、電文の送受信を担当する装置に対してのプログラムが作りやすいのである。
それは、マルチタスクを用いたプログラミングにおいても、シングルタスクを用いたプログラミングにおいても同様である。
 この送信権というタイミングを確保するための仕組みに使われる電文制御コードには「ENQコード」を採用する事が一般的である。
ここで、主局側が、ENQコードを受け付ける側にしておき、従属局側がENQコードを送出する側にしておいたとする。
主局側から送出される電文は、そのままのSEXとETXコードにかこまれた電文を従属局に送って従属局からのレスポンスを待つ。
従属局側から送出される電文は、その電文を送る前に、ENQコードを主局側に送り、その主局側のレスポンスを待つ。(ENQコードを受け取った主局側は、従属局側から来る電文を受け取る体制にしておいてから、従属局側へACKを返す事。ここで主局側は電文受付状態にする(一定時間従属局への受信待ち状態を作る)。これが、主局側が従属局側に対しての送信権の確保するタイミングを作る仕組み作りとなる。)
そして、ACKコードのレスポンスが返ってきたのならば、従属局側は、主局側に電文を送り、各電文のレスポンスを待って、次々と従属局側は電文を出し続ける。
しかし、ACKコードが返って来ず、STXとETXでかこまれた電文がやってくると、従属局側は、電文送信処理を止め、主局からの電文受信処理に専念する事となる。
(この場合の送信権というものとは、通信プロトコルを活用しているオンライン処理をするアプリケーション側のデーターの送受信をスムーズに行うための問題解決のための通信プロトコルによって解決する問題である。)
さて、従属局側はENQコードを送ってレスポンスとしてACKコードを受け取った時、従属局側は主局側に電文を送出するのだが、この時、電文エラーが発生したら必ずリトライシーケンスを使って、電文データーの復旧作業をする事とするのである。
そして、従属局側は、全ての電文を送り終えると、終了の電文を送るのである。
これで、主局側は、従属局側のENQコードが来るまで、電文を送り続けっぱなしでいる事ができるのである。
しかし、従属局側のデーター送信権についてだが、ENQコードで確保したとしても、主局側が、何かのミスで、通常の送信電文を送ったら、従属局側のデーター送信権というタイミングの確保をいつでも放棄する様に作っておく事。
その様に優先順位を付けてデーターの送受信処理を作成する事が肝要である。
 さて、まぁ~、この様な以上の仕様が考えられるが、でも、やはり、そこには、ある程度の工夫を付け加える事が必要であろう。
○ 電文を連続して送る時、1電文は、次のブロックがある時、電文の最後に使う制御コードをETXにするのではなくEOB(エンド・オブ・ブロック)コードにしておいて、最後の電文の場合ETXコードにする。
○ 通信回線で接続されているコンピューター同士は、接続確認する仕組みを作っておいて、通信回線が断線時の処理の仕様を作っておき、また、通信回線が復旧したら、復旧処理のいくつかを考え出してそれを仕様化するが、完璧な復旧をする事ができない場合には、ソフトで自動的にリカバリー処理をする仕様を考えてアプリケーションを作る事ができなければならない。
○ いったん電源を切って、電源を入れ直した時の事を考慮した仕様書が書ける様にしておく。
以上の様な事ができる様にしておかなければ、この装置は実際の運用において使い物に成る製品とは呼べず、それは、プロが作ったとは言えないシステムと呼ばれる事となるであろう。
 ところで、追加として、STXとETXの制御文字で囲われた通信電文の各文字は、ACKやNAKやENQなどの使われている制御文字を使ってはいけない。
それどころか、英数字カタカナ・キャラクターコード以外の文字を使ってはいけない。
特に、制御文字を使ってはいけない。
その理由とは、STXで始まった電文内容にエラーが発生した時、電文内容にACKやNAKやENQなる文字を認識してしまったら、余計な通信プロトコルが発生して理解しがたい通信エラーが発生する可能性がある。
だから、電文内容には、制御文字を使ってはいけないし、更に言えばキャラクターコード以外の文字を使ってはいけない。
ここに、以前、書いた、通信電文を確定する状態遷移図とそのマトリックスには、若干の修正が必要である事は確かである。
ここにそういう注意すべき追加点を付加しておく。



7.トランスペアレントな電文の送受信+ENQコードについて。

トランスペアレントな電文の形式は、次の通りであろう。
DEL+STX : 通信プロトコルの電文の始めという意味。
DLE+EOB : 通信プロトコルの電文のブロックの終わりという意味。
DLE+ETX : 通信プロトコルの最終電文の終わりという意味。
DLE+DLE : 電文内で認識するDLEコード。(DLE)
もし、電文の一番最後にチェックサムコードが追加されている場合、そのチェックサムコードが、DLEならば、DLEを一つ追加させて、DLE+DLEとする。

 トランスペアレントな電文に対してのレスポンスの形式は次の通りであろう。
DLE+ACK : 通信プロトコルの正常電文受信というレスポンスの意味。
DLE+NAK : 通信プロトコルの異常電文受信というレスポンスの意味。

 従属局から電文の送信権を確保するための組合せのコードは、次の通りであろう。
DLE+ENQ : 通信プロトコルの従属局から送信権確保の要求という意味。


主局が、受信すべき最初の組合せのコード。
DLE+STX 、 DLE+ACK 、 DLE+NAK 、 DLE+ENQ。
主局が、無視すべき最初の組合せのコード。
DLE+DLE。
それ以外のコードは無視。
もし、主局がDLE+STXを受信した時、特別に監視すべきコード。
DLE+DLE(電文コードとしてのDLEとして取り扱う)
DLE+EOB(通信プロトコルの電文のブロックの終わりという意味として取り扱う)
DLE+ETX(通信プロトコルの最終電文の終わりという意味として取り扱う)
DLE+STX(通信プロトコルの電文の始めという意味として取り扱い、元の電文を破棄して新たに電文を作り直す。)
DLE+(STX,DLE,EOB,ETX以外のコードの組み合わせの場合)は、電文破棄して最初から受信し直す。
それ以外のコードは、そのまま電文のコードとして受信する。
それは、単純に、ENQ,STX,EOB,ETXというコードが来た場合も、何も変換せず、そのまま取り扱うという事である。


 従属局が受信すべき最初の組合せのコード。
DLE+STX 、 DLE+ACK 、 DLE+NAK。
従属局が、無視すべき最初の組合せのコード。
DLE+DLE(これは、この組み合わせが来たらスキップして無視する事である。)
それ以外のコードは無視。
もし、主局がDLE+STXを受信した時、特別に監視すべきコード。
DLE+DLE(電文コードとしてのDLEとして取り扱う)
DLE+EOB(通信プロトコルの電文のブロックの終わりという意味として取り扱う)
DLE+ETX(通信プロトコルの最終電文の終わりという意味として取り扱う)
DLE+STX(通信プロトコルの電文の始めという意味として取り扱い、元の電文を破棄して新たに電文を作り直す。)
DLE+(STX,DLE,EOB,ETX以外のコードの組み合わせの場合)は、電文破棄して最初から受信し直す。
それ以外のコードは、そのまま電文のコードとして受信する。
それは、単純に、ENQ,STX,EOB,ETXというコードが来た場合も、何も変換せず、そのまま取り扱うという事である。
ただし、もし、電文の一番最後にチェックサムコードが追加されている場合、そのチェックサムコードが、DLEならば、DLEを一つ追加させて、DLE+DLEとする。

以上の様なコード変換するが、後は、トランスペアレントでない電文の送受信の仕様と同様な通信プロトコルを作れば、トランスペアレントな電文の送受信の仕様が完成する。

ただし、これは、私の空想した仕様であり、実際に運用した事が無いので、ちょいと自信が無い。
とりあえず、この仕様で通信プロトコルを作る場合、状態遷移図とマトリックスを書いてからプログラミングする事。
このプログラミングは、受信タスクの割り込み処理に主に使われる。



8.XON,XOFFコードについて。

 今までの通信プロトコルは、電文の送受信に関して、レスポンスが返ってきた。
そういう電文ならば、ほとんどは、XON,XOFFコードを使う事はないであろう。
だから、パケット通信では、まず、XON,XOFFコードを使う事はない。
しかし、無手順であり、一方的な電文の送信に関しては、XON,XOFFコードは重要になってくる。
電文を受信して、受信する側の電文バッファーがいっぱいになりそうであったのならば、XOFFコードを送信側に送って、送信する側に電文を送出するのを待ってもらう事とする。
また、電文を受信する側の電文バッファーに余裕が出てきたら、XONコードを送信側に送って、送信する側にたまっている電文を送出する事を要請するのに使うのである。
これは、特に、電文を送出する側の装置と電文を受信する側の装置の間に、電文を蓄積するためのバッファー装置を付加させた場合、良く使われるコードである。
XON,XOFFという通信制御のためのコードとは、無手順の通信プロトコルでは良く使われる通信プロトコルに活用される。



9.リクエストメニュー電文。

※ これは、オンライン機器の通信を自動化する事によって動かす事を目的とせず、オンライン機器の保守点検のために、他のコンソール端末によってオンラインで接続し手動で動かし、しかも、オンライン機器の内部状態を監視及びチェックするために向いている通信プロトコルについて解説する。なお、これには、リトライシーケンスやリカバリーの仕様を要求する事は無い単純な通信プロトコルである。

 これは、ポーリング電文の応用である。
今まで、電文を送ったら、そのレスポンスとして、ACKとかNAKが返ってきた。
しかし、レスポンスとは、その様な単純なもので良いのだろうか?
送信する電文によって、もっと、相手のコンピューターのいろんな内部の装置を動かしているタスクを動かしてコントロールしたり各装置を動かしている各タスクの内部情報を取得したりして、それをレスポンスとして送って返してよこしても良いのではないだろうか。
そこで、ここでは、ポーリング電文の変形版としてリクエストメニュー電文なるものを考えてみよう。
この場合、レスポンスが出るためには、いろいろと自動化されている通信プロトコルよりもかなり反応の遅いレスポンスになってしまうだろうが。
 さて、この場合、実際の電文は、どの様にするか?
送信する局の電文は、STX~ETXで囲われた電文を送る。
そして、それを受信した局は、送信された電文の内様に従って自分の装置を処理してその結果内容を、STX~ETXで囲われた電文を作って送り返すのである。
この時、レスポンスの電文は、正常に電文を受信した時は、それに応じた電文を送信して送り返せば良い。
また、電文の形を成していない電文を受信した場合、レスポンスを返す事を無視する。
電文の形をした電文を受信したが、それに対応する電文が無い場合、レスポンスに返す電文は、「NOT FIND」という内容にしても良いだろう。
この様に、自前で作る通信プロトコルは、いろんなバリエーションが考えて作る事ができるものである。
 特に加算電文でもないし、また、自動化させる通信プロトコルでも無い、手動で相手にメッセージを送るだけの通信プロトコルの設計は、余計なリトライシーケンスも無しでありその上通信バッファーを設ける必要が無しのまま、来たままの電文を素直に受け取って、エラーだったら無視し、正常受信したのならば、そのレスポンスとなるSTX~ETXで囲われた電文を送り返すだけで良いので通信プロトコルの設計は、かなり楽になる事であろう。

通信プロトコルの基礎。その1/4。著者:吉田作太郎

通信プロトコルの基礎。

 これは、データー通信の基礎である。
ここに、Aという装置とBという装置の二つの装置があったとする。
この二つの装置は、互いにデーターを送信したり受信したりする事ができたとしよう。
つまり、トランシーバーの様な装置だったとする。
この二つのトランシーバーが、互いに通信し合い一つのシステムを作る事としよう。
その時の二つのトランシーバーの間での互いの交信をスムーズに行う事を一番の目的として交信の手順を定めた仕様の事を通信プロトコルと呼ぶ。
この通信プロトコルは、その他にも、二番目の目的、三番目の目的など有り、さまざまなサービスが考え出されている。
ここで、オンラインとは二つの機械の間での通信を自動的にする処理の事を言い、オフラインとはこの二つの機械の間の通信を人間の手を仲介とする処理の事を言う。
また、二つの機械の通信装置の通信回線が一本であり、その一本の回線で送受信をまかなうハードウェアの仕様の事を半二重通信回線と呼ぶ。
また、通信回線が二本であり、その二本の通信回線で、一方を送信用専用、一方を受信用専用と定めてデーターの送受信をする事ができるハードウェアの仕様を全二重通信回線と呼ぶ。
さて、私の知る限り、この通信プロトコルにとって必要な技術は次の3点に集約される。
1. リトライシーケンス。
2. リカバリー。
3. ポーリングの技術。
この3点の事を理解してオンラインの通信プロトコルを設計すれば、だいたいどこに出しても申し分の無い商品として成り立つオンラインのアプリケーション・プログラムを設計する事ができるだろう。
ここで記述する技術とは、だいぶ昔によく使われた通信プロトコルではあり、RS232Cを用いたトランザクション・データー(通信電文)の通信プロトコルの基礎を中心に解説する。
通信処理とは、ノンストップが要求される。
伝送エラーが発生しても独自に自らの処理を続ける事が要求されるのである。
そこで、通常、通信にリトライする処理とポーリングして相手の状態を確かめリカバリーする処理を通信プロトコルに付け加えた。
こういう仕様を加えられた通信は、エラーが発生したらいろいろと復旧できる仕組みを持ち、電源を入れ直したらただちに復旧する事が自動的にできる。
また、装置が故障しても代わりの装置をつなげて電源を入れ直せば、自動リカバリー処理のためにシステムをスムーズに修復する事ができる。
それまでの仕様を実現するためのパラメーターをスケールアップしてゆく流れを中心に通信手順のメカニズムであるプロトコルの説明をしてゆく。
さて、補足として、通信プロトコルには「無視」という言葉が重要になってくる。
通信エラーが発生して、通信が混乱したら、へたな救済策を出すよりも、「無視」した方が、はるかに効果が絶大だからだ。
又、通信プロトコルのリトライシーケンスやリカバリー処理より、機械同士のコミュニケーションの設計とは記憶を共有する様に作るのがコツでもある。
しかし、こういう通信プロトコルというのがいかに巧妙で立派だとしても、これは機械の立場での事であり、実際の人間同士のコミュニケーションと通信プロトコルは違うものである。
実際の人間同士のコミュニケーションの場において「無視は良いですね。」と言ったら人格を疑われる事があるので、そういう言葉を使うにも注意が必要である事を付け加えておく。
人との関係とは、まず、挨拶。そして、言葉のかけ合いが、基本である。

 さて、私は、「無視のコミュニケーション」に説明すると、ほとんどの人間は、それは悪い事だと言い張る。
機械と人間とは違うとか言い出す。
で、ここで、あえて、無理とは分かっていながら、「無視のコミュニケーション」についての説明がしたい。

 無視とは、コミュニケーションを拒絶している事であろうか?
機械のプロトコルにおいての無視とは、単なる約束事であり、これは積極的なコミュニケーションをし続けている事である。
拒絶のコミュニケーションではなく、空のコミュニケーションである。
この空のコミュニケーションがあるからこそ、リトライシーケンスやリカバリー処理がスムーズにできるのであり、この空のコミュニケーションから多くの可能性を持つコミュニケーションを作り出す事が可能となるのである。
 無視のコミュニケーションとは、拒絶のコミュニケーションではなく、そこから多くの可能性を作り出す空のコミュニケーションであり、智慧のあるコミュニケーションとなる可能性を秘めている。
つまり、無視とは、すき間無くコミュニケーションする機械の中で自然発生的に生まれるアクシデントに対して、間を与え、空のコミュニケーションをする事を定義して、復旧運営する可能性を持たせるなどの智慧を作り出す事に役に立っている。
この空のコミュニケーションがあるおかげで、障害発生時、同じコミュニケーションの応酬によって偏りが発生しているプログラムに偏りを無くし、別のコミュニケーションに導いて障害を克服する事ができるプロトコルを構築する事ができるのである。
機械のコミュニケーションにおける無視とは、無関心である事とは違う。
助け合いを有効に行うために無視するのである。
 しかし、それでも、無視は良くないと強情に言う者がいれば、説得として、方便として、「それは間を置く事だ。」と言うしかないだろう。
こういうコミュニケーション論で苦しんでいる時、私の話を聞いた人は、「それは、無視とは違う。忍耐強く、愛を持って見守っている事だよ。」と言ってくれた人がいた。
人を説得する事とは難しいものだ。

 さて、機械のコミュニケーションとは何か?
私の世界では、始めに「存在」ありきである。
通信する相手が存在するか存在しないかを確かめる事が一番大切なのだ。
次に、存在する相手が、どの様な状態であるかを把握する事が大事なのだ。
そこから、やっと、コミュニケーションの本題に入ってゆく事ができる。
もし、「存在」が有るとしたら、相手を呼び出す電文を送り続ければ反応が返ってくるものである。
それは、一般社会において挨拶する事と似ている。
そして、その挨拶によって積極的なコミュニケーションをさせる事が、私の考える機械のコミュニケーションの姿なのだ。


<目次>

1.電文とトランザクション・データー。 6
2.一電文の送信。 7
2.1.送りっぱなし電文。 7
2.2.STX,ETXで電文を囲む。 7
2.3.トランスペアレントな電文。 9
2.4.トランスペアレントな電文との混合型電文。 13
3.レスポンスを求める電文。 14
3.1.リトライシーケンスの電文。 14
3.2.リトライシーケンスの重複をさける電文。 15
3.2.1.電文を二重にする。(押し出し電文) 15
3.2.2.電文にシーケンス番号を付ける。 16
3.3.トランスペアレントな電文のレスポンスの場合。 16
4.ポーリング電文を活用する技術。 17
4.1.主局からの電文の再構成。 18
4.2.主局からの電文のフォーマット。 20
4.3.従属局からのレスポンス用電文フォーマット。 20
4.3.1.従属局が送り出す、主局から受け取ったシーケンス番号について。 20
4.3.2.従属局が送り出す、主局から受け取った電文種類について。 21
4.3.3.従属局が送り出す、内部エラーメッセージについて。 21
4.4.Q電文のプロトコル。 21
4.5.P電文の活用。 22
4.6.レスポンスの間引き。 22
4.7.リセット電文の必要性。 23
4.8.その他。(ヘルスチェック) 23
4.9.クライアント・サーバー。 24
5.親局と複数の子局のある電文形式。(マルチポイントの電文) 25
6.トランスペアレントでない電文の送受信+ENQコードについて。 26
7.トランスペアレントな電文の送受信+ENQコードについて。 28
8.XON,XOFFコードについて。 30
9.リクエストメニュー電文。 31
10.ネットワーク通信の有用性。 32
11.パケット通信に関して。 33
11.1.パケット通信によるデジタル通信の中継局に関しての考察。 33
11.2.OSIとTCP/IP。 35
11.2.1.セッション層の工夫。 38
11.2.2.送信権の確保の工夫。(全4重通信の構想) 38
11.2.3.マルチタスクとパケット。 38
11.2.4.TCPとUDP。 40
11.2.5.データーリンク層によるネットワーク通信。 40
11.2.6.コミュニケーションとは記憶を共有する事だ。 40
11.3.ネットワーク通信のデバッグ環境。 41
12.オンライン処理の基本的な通信エラー対策に関して。 42
13.ノンストップのシステムを作る事。 43
14.ポーリングと人間関係。 44
15.通信プロトコルを作る時の苦労。 45
16.昔のBASICでの通信割り込みの問題。 47
17.データー通信とアプリケーション。 49



1.電文とトランザクション・データー。

トランザクション・データーとは、命令と情報を持った文字列の事である。
コンピューター間の通信に使われるトランザクション・データーの事を昔の通信プロトコルでは、電文と呼んだ。
ここでは、その電文の送受信のやりとりについて解説する。



2.一電文の送信。

 送信側と受信側がはっきりしている、1対1のコンピューター間の一方方向の通信について解説する。

2.1.送りっぱなし電文。
 特に無手順と呼ばれている通信プロトコルである。
むき出しのトランザクション・データーを通信電文として一文字ずつ送信し、受信する側は、その内容をチェックして正常ならばその受信電文のデーターを取り込み受け入れる。

2.2.STX,ETXで電文を囲む。
 送信側は、むき出しのトランザクション・データーの先頭に、「STX」コードを付け、終わりに「ETX」コードを付け、その後、エラーチェックコードを付加して、一つの通信電文を作る。
受信する側は、「STX」コードを同期してから通信電文を受け取り開始し、「ETX」コードを受信したら、その後のエラーチェックコードを参照して正常ならば受け取った「STX」から「ETX」まで囲われた通信電文を確定したとみなす。
異常ならば無視して、また、次に「STX」コードが来るまで待つ。
また、「STX」コードを受信して、「ETX」コードが来る前に「STX」コードが来たら、新たな「STX」コードから始まった電文受信して「ETX」コードを受信しエラーチェックコードをチェクして電文が正常であるかどうか確かめる。
その後、確定した通信電文のトランザクション・データーの内容を受信する側は見て、正常ならばその受信電文の内容を受け入れ、異常ならば無視する。
 次に第一のエラー制御について述べる。
RS232Cの通信において、通信する文字列の文字の一つ一つにパリティーチェックが入っており通信の異常を監視する。
「STX」コードを受信しても、途中でパリティーエラーが発生したら、その電文は無視して、次の「STX」コードを探して次の電文を受信する作業に入る。
 第二のエラー制御について述べる。
送信する側は、電文に「STX」コード、トランザクション・データーの文字列、「ETX」コードを付ける時に、送信電文のエラーチェックコードを作って「ETX」コードの後に付加する。
受信する側は、「STX」コードと「ETX」コードで囲まれた電文の内容からエラーチェックコードを作り出し「ETX」コードの次にあるエラーチェックコードと一致するか確かめて一致したら正常電文とみなして、受け取り開始していた通信電文を確定したとみなす。
エラーチェックコードを作る方法とは、通信電文に使う文字列の文字の一つ一つを、加算して作ったり、EORして作ったり、CRCコードを生成して作ったりする。
通信プロトコルを作る際には、エラーチェックコードの生成には何を選ぶかを決めて運用する事。
ただし、第二のエラー制御は通信プロトコルにより無くても良い。
これらの事を考えて受信する側の通信電文を確定する状態遷移図の手順を以下に示す。
※ 状態遷移図内の赤字は、状態ではなく処理内容を記述する。

  ( 始 め )
     ↓
(「STX」コード検出(同期) )←――――――――――
     ↓              ↑      ↑
(電文受信処理)←(新たに)      │      │
  │  │     ↑ (受信していた文字列を無視)│
  │  │(受信していた文字列を無視)↑      │
  │  ↓     ↑        │      │
  │ 「STX」コードを検出 )   │      │
  ↓                 │      │
「ETX」コード検出          │      │
  ↓                 │      │
エラーチェックコードと一致――――→(不一致)    │
  ↓(一致)                    │
受信電文確定 ―――――――――――――――――――→│
                           │
○ 文字カウントして長すぎる電文:          │
    受信していた文字列を無視して――――――――→│
○ パリティーエラーを検出した電文:         │
     受信していた文字列を無視して―――――――→│

上図のマトリックス(初期値は①)
│    1  2 3 4  5  6 7
│①   ②  ― ― ×  ×  ① ①
│②  (②) ② ③ ×  ×  ① ①
│③   ④  ④ ④ ×  ×  ① ①
│④   ×  × × ①1 ①2 ① ①

上のマトリックスの各項目
│○ マトリックスの縦列
│  ① 「STX」コード検出(同期)
│  ② 電文受信処理
│  ③ 「ETX」コード検出
│  ④ エラーチェック
│○ マトリックスの横列
│  1.STXコード受信
│  2.STX,ETX.以外のコード受信
│  3.ETX.コード受信
│  4.エラーチェックコードと一致
│  5.エラーチェックコードと不一致
6.受信処理が文字カウントして長すぎる電文
│      (データーレングス・オーバー)
│  7.パリティーエラーの検出
│○ マトリックス内の各項目についての説明。
│  ―  無視。
│  ×  対象外(チェックしない)。
│  ①  受信電文レングスを0にして、
      「STX」コードを検出待ち処理。
│  ①1 受信電文確定処理実行して①の処理を実行。
│  ①2 受信電文不確定処理実行して①の処理を実行。
│  ②  電文受信処理。電文レングスのカウント。
│ (②) 新たに「STX」を受信したので、
│     今まで受信した電文を破棄すると同時に、
│     受信電文レングスのカウントを1にして、
│     新たに「STX」コードから始まる電文を受信する。
│  ③  「ETX」コード検出。
│  ④  エラーチェックコード処理。

 この状態遷移図とは、状態遷移図ではない。単なるフロチャートだと言う人間がいるだろう。
状態遷移図とは、イベントが有って、それによって状態が移り変わる。
これを表すのに、二種類の状態遷移図が存在する事となるだろう。
○ イベントに左右されず状態の変化だけに注目した状態遷移図とマトリックス。
○ 全てのイベントに対して対応して記述した状態遷移図とマトリックスである。
人によっては、全てのイベントに対して対応して記述した状態遷移図の事を単なるフロチャートだと言う人間が存在するが、プログラマーに仕様を渡して仕事をさせるには、全てのイベントに対して対応して記述した状態遷移図とマトリックスが必要な時もある。

2.3.トランスペアレントな電文。
 「STX」,「ETX」の電文では、「STX」コードと「ETX」コードを電文として送る事ができない。
そこで、どんな文字列の電文でも送れる電文の必要性が出てきた。
それができる電文をトランスペアレントな電文と呼ぶ。
HDLCプロトコルでは、トランスペアレントな電文を送れるが、電文コード主体のプロトコルでは、新たに「DLE」コード(データーリンクエスケープコード)を利用して、次の様なトランスペアレントな電文を作るのである。
送信側は、むき出しのトランザクション・データーの先頭に、「DLE」+「STX」の2つのコードを付け、終わりに「DLE」+「ETX」コードの2つを付け、その後、エラーチェックコードを付加して、一つの通信電文を作る。ここで、トランザクション・データーの中身に、1つの「DLE」コードがあったとしたら、「DLE」+「DLE」と2つのコードに変換して電文を作る。
次に受信する側は、「DLE」+「STX」の2つの連続するコードを同期してから通信電文を受け取り開始し、「DLE」+「ETX」の2つの連続するコードを受信したら、その後のエラーチェックコードを参照して正常ならば受け取り開始した通信電文を確定したとみなす。
その後、確定した通信電文のトランザクション・データーの内容を受信する側は見て、正常ならばその受信電文の内容を受け入れる。
また、電文を受信して「DLE」コードを確認したらその次も「DLE」コードならば、一つの「DLE」コードとして取り扱って電文受信処理を続ける。電文受信を開始して、「DLE」+「ETX」でも「DLE」+「DLE」コードでもなかったら、異常電文としてその電文の文字列を無視する。
 次に第一のエラー制御について述べる。
RS232Cの通信において、通信する文字列の文字の一つ一つにパリティーチェックが入っており通信の異常を監視する。
「DLE」+「STX」コードを受信しても、途中でパリティーエラーが発生したら、その電文は無視して、次の「DLE」+「STX」コードを探して次の電文を受信する作業に入る。
 第二のエラー制御について述べる。
送信する側は、電文に「DLE」+「STX」コード、トランザクション・データーの文字列、「DLE」+「ETX」コードを付ける時に、送信電文のエラーチェックコードを作って「ETX」コードの後に付加する。
受信する側は、「DLE」+「STX」コードと「DLE」+「ETX」コードで囲まれた電文の内容からエラーチェックコードを作り出し「ETX」コードの次にあるエラーチェックコードと一致するか確かめて一致したら正常電文とみなして、受け取り開始していた通信電文を確定したとみなす。
エラーチェックコードを作る方法とは、通信電文に使う文字列の文字の一つ一つを、加算して作ったり、EORして作ったり、CRCコードを生成して作ったりする。
通信プロトコルを作る際には、エラーチェックコードの生成には何を選ぶかを決めて運用する事。
ただし、第二のエラー制御は通信プロトコルにより無くても良い。
これらの事を考えて受信する側の通信電文を確定する手順の状態遷移図を以下に示す。
※ 状態遷移図内の赤字は、状態ではなく処理内容を記述する。

  ( 始 め )
     ↓
( 「DLE」コード検出(同期) ) ←―――――――――――――
     ↓                 ↑        ↑
( 「STX」コード検出  )→( 「STX」以外 )     │
     ↓                          │
(   電文受信処理    )←――――――――――――――  │
     ↓             ↑         ↑  │
( 「DLE」コード検出  )  (新たに)       │  │
 │   │  │   │      │         │  │
 │   │  │   │ (受信していた文字列を無視) │  │
 │   │  │   ↓      ↑         │  │
 │   │  ↓  「STX」コードを検出 )     │  │
 │   │(「DLE」コード検出:           │  │
 │   │   1文字の「DLE」コードとして     │  │
 │   ↓      取り扱い電文受信処理へ)――――→│  │
 │ 「ETX」コード検出                   │
 │   ↓                          │
 │ エラーチェックコードと一致                │
 │   │(一致)  ↓(不一致)              │
 │   │    (受信していた文字列を無視)―――――――→│
 │   ↓                          │
 │ 受信電文確定 ―――――――――――――――――――――→│
 ↓                              │
「DLE」、「STX」,「ETX」以外のコード:        │
       受信していた文字列を無視)―――――――――――→│
                                │
  ○ 文字カウントして長すぎる電文:             │
            受信していた文字列を無視して―――――→│
  ○ パリティーエラーを検出した電文:            │
            受信していた文字列を無視して―――――→│


上図のマトリックス(初期値は①)
│    1  2  3 4  5  6  7 8
│①   ②  ―  ― ―  ×  ×  ① ①
│②   ① (③) ① ①  ×  ×  ① ①
│③   ④  ①  ③ ①  ×  ×  ① ① 
│④   ③ (③) ① ⑤  ×  ×  ① ①
│⑤   ⑥  ⑥  ⑥ ⑥  ×  ×  ① ①
│⑥   ×  ×  × ×  ①1 ①2 ① ①

上のマトリックスの各項目
│○ マトリックスの縦列
│  ① DLE+STXのDLEコード受信処理(同期)
│  ② DLE+STXのSTXコード受信処理(同期)
│  ③ 電文受信処理
│  ④ 電文受信処理「DLE」コード検出。
│  ⑤ 電文受信処理「DLE+ETX」コード検出。
│  ⑥ エラーチェクコード処理。

│○ マトリックスの横列
│  1.DLEコード受信
│  2.STXコード受信
│  3.DLE,STX,ETX.以外のコード受信
│  4.ETX.コード受信
│  5.エラーチェックコードと一致
│  6.エラーチェックコードと不一致
│  7.受信処理が文字カウントして長すぎる電文
│    (データーレングス・オーバー)
│  8.パリティーエラーの検出
│○ マトリックス内の各項目についての説明。
│  ―  無視。
│  ×  対象外(チェックしない)。
│  ①  受信電文レングスを0にして、
│     「STX」コードを検出待ち処理。
│  ①1 受信電文確定処理実行して①の処理を実行。
│  ①2 受信電文不確定処理実行して①の処理を実行。
│  ②  DLE+STXのSTXコード受信処理。
│     受信電文レングスのカウントを1に設定。
│  ③  電文受信処理。電文レングスのカウント。
│ (③) 新たに「DLE+STX」を受信したので、
│     今まで受信した電文を
│     破棄すると同時に、
│     受信電文レングスのカウントを2にして、
│     新たに「DLE+STX」コードから始まる
│     電文を受信する。
│  ④  電文受信処理「DLE」コード検出。
│  ⑤  電文受信処理「DLE+ETX」コード検出。
│  ⑥ エラーチェクコード処理。

ただし、追加として、もし、電文の一番最後のチェックサムコードが、DLEならば、DLEを一つ追加させて、DLE+DLEとする。

2.4.トランスペアレントな電文との混合型電文。
 受信側が、最初に「DLE」コードを受信したら、トランスペアレントな電文として処理し、最初に「STX」コードを受信したら、一般の電文を受信したとして電文を処理してゆく事にすれば、どちらとも対応可能な装置を作る事が可能かもしれない。

「DLE」 : データー リンク エスケープ コード。
        (デリートとは違う)
「STX」 : スタート オブ テキスト   コード。
「ETX」 : エンド  オブ テキスト   コード。



3.レスポンスを求める電文。

 ここから、品質の良い通信をするための通信プロトコルの領域に入ってくる。
通信プロトコルとは、通信の仕組みを作る事である。
さて、今まで、受信する側は、障害のある電文を無視してきた。
今回は、障害のある電文が来たら、電文の再送を要求する電文を出して送信側に電文を再送してもらう。
また、障害が無く正常に受信されたら、送信側に正常ですという応答(レスポンス)を出して次の電文を送ってもらう事とする。
また、電文を送信して、レスポンスが返って来なかったら、送信する側は、また電文の再送をして確実に受信する側に電文を受信してもらう仕組みも作る。
 電文の異常は、送信側が作った時に発生するものと、通信の途中でノイズが入って発生するものがある。
デバッグ時には正しい電文と異常な電文を作って動作確認して、送受信側の装置のプログラムを作る。
実用段階において送信側が正しい電文が作れずに電文を送信する事が無い様にきちっとデバッグして作る事。
もし、ここで、そういう事態になったとしたら、この場合の通信プロトコルは、通信途中でノイズや切断があっての電文異常と判断して、送信側から電文を再送してもらって正しい電文を受信しようとする事となるだろう。

3.1.リトライシーケンスの電文。
 送信側の電文を受信したら、受信側は、確実にレスポンスを送信側に出してもらう。
正常に受信したら、受信側は、「ACK」コードを送信側に送る。
受信している電文にパリティーエラーなどの異常が発見されたならば、受信側は、「NAK」コードを一回だけ送信側に送り、電文受信は今までの受信電文を捨てて、また最初に「STX」コードのある電文が来るのを待つ。
また、受信した電文の終りに「ETX」コードの後のエラーチェックコードを確かめて電文異常と判断したならば「NAK」コードを送信側に送る。
「NAK」コードを受信した送信側は、受信する側にまた同じ電文を送信する。
電文を送信する側が電文を送って、なかなか電文を受信する側からレスポンスが帰って来なかった場合、電文異常があって受信する側がその電文を無視したとみなして電文を再送する。(タイムアウト処理)
この様に電文を送信する側に電文を再送してもらう仕組みの事をリトライシーケンスと呼ぶ。
リトライシーケンスとは、タイムアウト処理で判別した受信側からのレスポンスの無応答にも受信側からの「NAK」コードのレスポンスを受信しても働く。
通信プロトコルでは、このリトライシーケンスを実行するにも限度を設ける。
電文を送信する側は、「NAK」用と無応答用に限度を設けて、その回数をオーバーしたら、通信が切断したものとみなしてリトライシーケンスのセッションを終了する。
通常、このリトライシーケンスの限度は、どちらも3回あたりが適正だとされている。
 さて、受信する側が電文異常を探知しても、「STX」から始まっている一電文を受信した訳では無い場合、「NAK」を出さない。
これは、電文の無視ではなく、電文の形を持たない文字列の無視である。
それを無視しないで「NAK」のレスポンスを出すと、受信する側は、一電文に対してたくさんの「NAK」を出力し続ける事態が発生し、それにより異常なリトライシーケンスが発生して送信する側は多くの電文を出力する事により通信が混乱してしまう結果を生むものである。
だから、こういう場合、無視して無応答でなければならない。

3.2.リトライシーケンスの重複をさける電文。
受信側が正常な電文を受け取って「ACK」コードを送信したのに、送信側が伝送路のノイズなどの影響で「ACK」を受信できなかった場合、送信側はリトライシーケンスによって同じ電文を送信する。
この時、受信側は同じ電文を重複して受け取ってしまう。
電文が重複しても大丈夫なトランザクション・データーなら問題無いが、電文が重複して二重になるといけないトランザクション・データーの場合、この異常に対応する手段が必要とされる。
ここでは、そのプロトコルについて考える。
○ 電文が重複しても許される電文:上書き電文。(問題無し)
○ 電文が重複したら異常となる電文:加算電文など。(課題となり解決策を以降説明)

3.2.1.電文を二重にする。(押し出し電文)
 一回目の電文にデーターを送り、二回目の電文にそれを承認する電文を送る。
受信する側は、一回目の電文を正常(正常とはトランザクション・データーの内容もチェックする事である)に受信したら、そのトランザクション・データーを記憶し内容を実行しないで送信する側に「ACK」のレスポンスを返す。
ここで、二回目に送るはずの承認する電文が来ないで新たな正常な電文が来たら、前のトランザクション・データーの内容を排除して、新たなトランザクション・データーの内容を上書きして記憶し内容を実行しないで送信する側に「ACK」のレスポンスを返す。
次に送信する側は、一回目の電文に対して承認を与える電文を二回目に送る。
ここで受信する側は、二回目の承認を与える電文を受け取ると一回目に記憶しておいたトランザクション・データーを有効とみなして受信するコンピューターは、そのトランザクション・データーの内容を実行すると同時に送信する側に「ACK」のレスポンスを返す。
一度承認した電文に対して二重の承認電文を受け取ったら、すでにトランザクション・データーの内容を実行したので無効とするが、送信する側には「ACK」のレスポンスを返す。
これにより、リトライシーケンスの問題点である、送信側の「ACK」コードの受信エラーのために発生する電文の二重送信のために発生する受信側の電文の二重実行がさけられる。
これを私は「押し出し電文」と名付ける。

3.2.2.電文にシーケンス番号を付ける。
 電文にトランザクション・データーとは別にヘッダーを設けてそこにシーケンス番号のエリアを設けて取り付ける。
電文を送信する側のシーケンス番号は、初期値は「0」から始まる。
そして、電文を送信するたびに1つずつカウントアップされる。
そして、MAXになったら、今度は「1」から始まってカウントアップされる。
 受信する側は、電文が正常ならば、レスポンスにシーケンス番号を取り付けて送信側に送り、電文の内容を保存する。
そして、次の正常な電文が来たら、以前の電文の内容が承認されたものとして実行して、「ACK」にシーケンス番号を取り付けてレスポンスを返す。
また、「NAK」を送信する際にもシーケンス番号を付けてレスポンスを返す。
連続する電文は、シーケンス番号を取り付けて次々に送信するが、次に送る電文が無いとすると、以前の電文の内容を承認するための押し出し電文を送信して、受信側に以前の電文を承認させる。
 送信する側は、シーケンス番号を取り付けて送信するが、受信する側は、送信する側の電文のシーケンス番号が順番に来ているかチェックして、順番通りになっていないとエラーが発生したとみて、エラーが回復するまで電文受信を拒否する。

3.3.トランスペアレントな電文のレスポンスの場合。
 通常の電文のレスポンスの場合は、「ACK」、「NAK」であるが、「DLE」コードを使ったトランスペアレントな電文のレスポンスの場合は、「DLE」+「ACK」、「DLE」+「NAK」のコードを使うらしい。

リトライするCPUの構想。(CPU設計にデーター通信のリトライシーケンスを応用) 著者:吉田作太郎

リトライするCPUの構想。(CPU設計にデーター通信のリトライシーケンスを応用) 著者:吉田作太郎
本文
信頼性の高いCPUの研究(リトライするCPU)

目次
1.リトライシーケンスのあるCPUについての構想。 2
2.構成と動作。 4
3.コマンドとレジスター構成。 6
4.コマンドの解説。 7
(1)条件ジャンプ。(アブソリュート アドレス) 7
(2)条件ジャンプ。(相対 アドレス) 7
(3)無条件ジャンプ。(アブソリュート アドレス) 7
(4)無条件ジャンプ。(相対 アドレス) 7
(5)PUSH レジスター。 8
(6)POP レジスター。 8
(7)CALL 飛び先アドレス。(サブルーチンコール) 8
(8)RET。(リターン) 9
(9)IRQ発生時。 9
(10)IRET。(リターンインターラプト) 9
(11)「AC1 ← AC1(演算)AC2」。 10
(12)「転送命令、(IY)+ ← (IX)+」。 12
(13)「転送命令、(IY)ー ← (IX)ー」。 12
5.CPUのレジスター構成再考。 13
6.暴走するCPUをソフトウエアによって対処する方法。 14




1.リトライシーケンスのあるCPUについての構想。

コンピュータのCPU自身の異常動作についての対策について考えた。
ソフトウエアで、対応できる事柄は、各処理を実行した後にチェックライトしながら二度演算しなおすとか、CPUが、プログラムカウンターの異常でインストラクションのインタープリトが、異常になっても、アセンブラ命令の中にあるNOP(ノー オペレーション)命令の活用で、インタープリトする機能を正常にしなおせる様にするとか、CPUが、異常を検知した時(メモリーエラーや、ウオッチドックタイマーによるタイムアウトなどによる)、ソフトウエアで、異常処理を実行してもらうなどの一般的な対応がある。

私は、CPUをコミュニケーションする装置と考え、エラーを検出したら、コマンドを実行するCPU自信の内部状態が遷移する各フェーズに対して、リトライシーケンスを実行する事により、障害を克服する手段を考えた。(リトライシーケンスを行っても異常の場合はCPU異常を通知しなければならないが、ここでは、それについて述べない。)
エラー検出に関して言えば、同じ装置にCPUを二つ以上置いて、互いの内部の状態を比較し、常に同一の状態になっているかをチェックする事があげられる。

さて、CPUについて、命令の実行から考えると以下の機能が、必要である。
 ① データーの転送(メモリー転送)
 ② データーの演算(A+1 → Aなど)
 ③ プログラムの分岐(JMP,CALL命令、割り込み処理の実行)
これを再実行(リトライ)すると、次の問題が、生じる。
 ① 再実行による対応は、OK
   但し、移動先をまちがえた場合、相手先のメモリーを壊す。
 ② 2項演算を行っているものは、全て演算内容が壊れる。
   例) A+1→A をリトライすると 
     ((A+1)+1)→Aとなり
     演算内容が、破壊される。
 ③ プログラムカウンターの変更、
   スタックポインターの変更及び、データー転送がある。
   この時、PC(プログラムカウンター)、
   SP(スタックポインター)というCPU
   内部のレジスターに演算動作がされる。
   その演算の保証が、必要である。
この問題の解決方法について考える。
 ① リトライシーケンスは、可である。
   但し、移動先をまちがえて、
   壊れてしまったメモリーへの対応は、対策はない。
 ② 2項演算を使わず、3項演算を使って対応。
   どうしても、二項演算が、必要な場合、
   二つのフェーズに分けて演算する。
   例) 「A+1→A」 →
        (第一フェーズ、3項演算)   A+1→B
        (第二フェーズ、データー転送)  B→A
     という2つの独立したフェーズに分離して、命令を実行する。
 ③ 分岐命令をPC,SPの演算命令と、
   データー転送命令とに分けて、問題を整理
して考える。



2.構成と動作。

さて、これら命令を実行するCPUの構造について考える。

 ┌─CPU────────────┐  ┌───―───┐
 │┌───┐  ┌──────┐ │  │ プログラム │
 ││コント│←─┤命令フェッチ│ │  │       │
 ││ローラ│  │レジスター │←┼────┌───┐ │
 │└───┘  └──────┘ │┌──→│命 令│ │
 │       ┌──────┐ ││ │ └───┘ │
 │       │プログラム │ ││ │   │   │
 │       │カウンター │─┼┘ │   ↓   │
 │       └──────┘ │  │   ↓   │
 │       ┌──────┐ │  ├───―───┤
 │       │スタック  │ │  │       │
 │       │ポインター │ │  └───―───┘
 │       └──────┘ │  │       │
 │       ┌──────┐ │  ├───―───┤
 │       │演算    │ │  │       │
 │       │レジスター │─┼───→┌──―─┐│
 │       └──────┘←┼────│データー││
 └────────────────┘  │ └──―─┘│
                     │       │
                     └────―──┘
の構造になっている。
これは、次の様な動作をする。
 ① PC(プログラムカウンター)に示されたプログラム命令を
   命令フェッチレジスターに入れる。
   この時、PCは、1命令分、カウントアップする。
 ② 命令フェッチレジスターの内容をコントローラが、
   理解し、命令を実行する。
   この時、PC,SP,演算レジスター、メモリーの状態は、
   命令フェッチレジスター
   の内容を基にデーターを変化させる。
これを式にすると、
 ① (命令フェッチレジスター) ← (PC)+
 ② 命令の実行
の二つのフェーズに分かれて命令を実行する。
ここで、注意しなくてはいけないのは、①の段階で、正常なのに、エラー検出して、リトライすると、PCが、移動して、再実行したい命令の次の命令を実行してしまう。
これは、PCが、二項演算の要素を持っているためである。
ここで、PCを三項演算として、取り扱うために、PCの値を一時保管してもらうために、WPC(ワークPC)なるレジスターを作る。
そして、命令の実行を次の様に展開する。
 ① (命令フェッチレジスター) ← (PC), WPC ← PC
 ② 命令フェッチレジスターの実行
 ③ PCの移動「PC←WPC+実行した命令の長さ」
この3つのフェーズの各段階は、それぞれリトライしても大丈夫だが、その再実行の相関関係を表にしてみると、次の様になる。
┌────┬─────────────────┐
│    │   エラーリトライ       │
│フェーズ├─────┬─────┬─────┤
│    │①の再実行│②の再実行│③の再実行│
├────┼─────┼─────┼─────┤
│ ①  │  ○  │  X  │  X  │①から、再実行可
├────┼─────┼─────┼─────┤
│ ②  │  ○  │  ○  │  X  │①から、再実行可
├────┼─────┼─────┼─────┤
│ ③  │  X  │  X  │  ○  │③をリトライ
└────┴─────┴─────┴─────┘するしかない
     ( ○:再実行可/ X:再実行不可 )
これより、1命令をフェーズに分かれての再実行は、①②か、③のフェーズに分かれて可能となる。



3.コマンドとレジスター構成。

この考え方を基に、ノイマン型コンピュータの命令を再度、考え直す。
(基本的に、2項演算のフェーズのある項目を3項演算に分解して、物事を考える。)
ノイマン型のコンピュータの主なCPUの動作は、次の通りである。
 ☆ データー転送
 ☆ データー演算
 ☆ JMP命令(無条件、条件ジャンプ)
 ☆ サブルーチンコール
 ☆ 割り込みサービス
これらについて、基本的なコマンド実行についての解説をしながら、CPUの基本的なレジスター構成を模索する。
まず、最初に考えられる必要なレジスターは、次の通りである。
IFR:インストラクション フェッチ レジスター
           (コマンドをフェッチするために必要)
ILR:インストラクション レングス レジスター
           (フェッチしたコマンドのレングスを記憶するためのレジスター)
FR :フラグレジスター
PC :プログラムカウンター
WPC:ワーク プログラムカウンター
SP :スタックポインター
WSP:ワーク スタックポインター

これを基に、今まで示した3つの段階(フェーズ)に合わせて、各コマンドの実現のための、CPU内部のデーターの動きをさぐってみる。
ここでは、一つのフェーズにある複数のコマンドは、同時に実行できる様にできている。



4.コマンドの解説。

(1)条件ジャンプ。(アブソリュート アドレス)

 ① インストラクション フェッチ IFR ←─┬──(PC)
                  ILR ←─┘
 ② IF 条件一致
      THEN  WPC ← JMP先(IFRの内容により)
      ELSE  WPC ← PC + ILR
   ENDIF

 ③ PC ← WPC

(2)条件ジャンプ。(相対 アドレス)

 ① インストラクション フェッチ IFR ←─┬──(PC)
                  ILR ←─┘
 ② IF 条件一致
      THEN  WPC ← PC + 相対JMP先
                      (IFRの内容により)
      ELSE  WPC ← PC + ILR
   ENDIF

 ③ PC ← WPC

(3)無条件ジャンプ。(アブソリュート アドレス)

 ① インストラクション フェッチ IFR ←─┬──(PC)
                  ILR ←─┘
 ② WPC ← JMP先(IFRの内容により)

 ③ PC ← WPC

(4)無条件ジャンプ。(相対 アドレス)

 ① インストラクション フェッチ IFR ←─┬──(PC)
                  ILR ←─┘
 ② WPC ← PC + 相対JMP先(IFRの内容により)

 ③ PC ← WPC

次に、サブルーチンコール命令を考える前に、よく使われるスタック操作命令について考える。

(5)PUSH レジスター。

 ① インストラクション フェッチ IFR ←─┬──(PC)
                  ILR ←─┘
 ② (SP- レジスターレングス) ← レジスター
    WSP ← SP - レジスターレングス
    WPC ← PC + ILR

 ③ SP ← WSP
   PC ← WPC

(6)POP レジスター。

 ① インストラクション フェッチ IFR ←─┬──(PC)
                  ILR ←─┘
 ②  レジスター ← (SP)
    WSP ← SP + レジスターレングス
    WPC ← PC + ILR

 ③ SP ← WSP
   PC ← WPC

次にサブルーチンコールについて考える。

(7)CALL 飛び先アドレス。(サブルーチンコール)

 ① インストラクション フェッチ IFR ←─┬──(PC)
                  ILR ←─┘
 ② (SP- プログラムカウンターレングス)←PC+ILR
    WSP ← SP - プログラムカウンターレングス
    WPC ← IFRにある飛び先アドレス

 ③ SP ← WSP
   PC ← WPC

(8)RET。(リターン)

 ① インストラクション フェッチ IFR ←─┬──(PC)
                  ILR ←─┘
 ②  WPC ← (SP)
    WSP ← SP + プログラムカウンターレングス

 ③ SP ← WSP
   PC ← WPC

次にインターラプト(IRQ)発生について考える。
メモリー、レジスター間の転送が、2つあるので、(9)と(10)の実行では、・のフェーズに2クロックが、最低限、必要である。

(9)IRQ発生時。

 ① インストラクション フェッチ 無し

 ② (SP- PCレングス ー 0) ← PC + ILR
   (SP- PCレングス ー FRレングス) ← FR
    WSP ← SP - PCレングス ー FRレングス
    WPC ← IFRにある飛び先アドレス

 ③ SP ← WSP
   PC ← WPC

(10)IRET。(リターンインターラプト)

 ① インストラクション フェッチ IFR ←─┬──(PC)
                  ILR ←─┘
 ②  FR  ← (SP)
    WPC ← (SP + FRレングス)
    WSP ←  SP + FRレングス+ PCレングス 

 ③ SP ← WSP
   PC ← WPC

ここで、データー演算命令について考える。
ここでは、3項演算を中心として問題を進めているので、演算レジスターは、まず、3つ必要である。
また、レジスター間のデーターの移動に対しても演算レジスターが、必要とされるので、最低限、演算レジスターは、合計4つ必要である。
しかし、今まで、2項演算の要素を、フェーズ分けしてきて、リトライシーケンスを可能としてきていた。
だから、ここでも、2項演算でも、今までのフェーズを利用したリトライシーケンスが、可能な演算方法を考えてみる。
ここでは、その方法を説明する。
その説明のために、ここでは、レジスターを3つ登場させる。
AC1:アキュムレータ1
AC2:アキュムレータ2
WKR:演算ワークレジスター

(11)「AC1 ← AC1(演算)AC2」。

 ① インストラクション フェッチ IFR ←─┬──(PC)
                  ILR ←─┘
 ② WPC ← PC + ILR
   WKR ← AC1(演算)AC2

 ③ PC  ← WPC
   AC1 ← WKR

次にデーター転送命令について、考える。
データー転送には、転送元と転送先がある。
まず、ここでは、I/OポートのデーターのREAD/WRITの信頼性については、対象としない。
I/OポートのデーターREADは、スイッチの入力などのチャタリングなどの様なノイズが、発生する事が予想され、不確定な値になり続ける場合がある。
また、データーWRITは、書いたデーターを読み直す事は、一般にはできないためである。
CPUを中心としたデーター転送には、4つの種類がある。
 Ⅰ.メモリー → レジスター(最低限1クロック必要)
 Ⅱ.レジスター→ メモリー (最低限1クロック必要)
 Ⅲ.レジスター→ レジスター(最低限1クロック必要)
 Ⅳ.メモリー → メモリー(メモリーアクセスを2度行うため最低限2クロック必要)
ここで、データー演算命令実行時には、(11)で使われた・以外の転送も、本来は必要である。
さて、転送元のメモリーのデーターの信頼性のチェックには、2度読みが考えられる。
また、転送先のデーターの信頼性に関しては、一度、転送したデーターを読み直す事が、考えられる。
ここにもバッファとしてのワークレジスターの必要性を感じる。
但し、ここでは、複数のCPUを使ってデーターをチェックしているので、エラーは、そこからも検知できるのでチェックは、省略できるが、その中で省略できない事は、CPUが、メモリーへデーター転送した時に、一度書き込んだ命令を読み直す事ぐらいであろう。
但し、この時、CPUが、データーの書き込み先をまちがえた場合、壊れてしまったメモリーのデーターへの対応策は、CPU独自のハードでの対策だけでは、不可能である。(ソフトウエアを含めた障害対策が、必要である。)

 さて、CPUには、アドレスレジスターをインデックスレジスターとして、活用するととても便利である。
ここでは、メモリーtoメモリー転送に便利なレジスターを取り入れて、コマンドを2つ作ってみる。
IX :インデックスレジスターX
IY :インデックスレジスターY
WIX:ワークインデックスレジスターX
WIY:ワークインデックスレジスターY
さて、(IY)←(IX)へ、データー転送時、メモリーアクセスを2度行うためこの部分に最低限2クロックが、必要である。




(12)「転送命令、(IY)+ ← (IX)+」。

 ① インストラクション フェッチ IFR ←─┬──(PC)
                  ILR ←─┘
 ② (IY) ← (IX)
    WIX ← IX + 転送1ワードレングス
    WIY ← IY + 転送1ワードレングス
    WPC ← PC + ILR

 ③ PC  ← WPC
   IX  ← WIX
   IY  ← WIY

転送命令には、逆アドレス方向の転送命令も必要なので、次の命令も付加する。

(13)「転送命令、(IY)ー ← (IX)ー」。

 ① インストラクション フェッチ IFR ←─┬──(PC)
                  ILR ←─┘
 ② (IY) ← (IX)
    WIX ← IX ー 転送1ワードデーターレングス
    WIY ← IY ー 転送1ワードデーターレングス
    WPC ← PC + ILR

 ③ PC  ← WPC
   IX  ← WIX
   IY  ← WIY



5.CPUのレジスター構成再考。

ここで、今までリトライするCPUに必要であった基本的なレジスター構成は、以下の様になる。

IFR:インストラクション フェッチ レジスター
    (コマンドをフェッチするために必要)
ILR:インストラクション レングス レジスター
    (フェッチしたコマンドのレングスを記憶するためのレジスター)
FR :フラグレジスター
PC :プログラムカウンター
WPC:ワーク プログラムカウンター
SP :スタックポインター
WSP:ワーク スタックポインター

AC1:アキュムレータ1
AC2:アキュムレータ2
WKR:演算ワークレジスター

IX :インデックスレジスターX
IY :インデックスレジスターY
WIX:ワークインデックスレジスターX
WIY:ワークインデックスレジスターY

プログラマーが、変数として、ユーザが、活用できるレジスターは、
FR,SP,AC1,AC2,IX,IY
その他デバックに注目しなければならないレジスターは、
PC
である。
最後に、リトライするCPUには、3つのフェーズが、必要で、最低限3クロック必要である。
ここで、CPUに命令フェッチするパイプライン処理を追加した場合①のフェーズを短縮できるので、最高1/3近くまでしか処理時間を短縮できないだろうと思われる。



6.暴走するCPUをソフトウエアによって対処する方法。

 CPUを動かす時、異常なコードをCPUのインストラクションが解析すると、エラートラップを発生させて、CPUに設定されたメモリー領域のプログラムを実行するという方法論が使えるCPUがある。
こういうCPUは、また、CPUのエラーとラップを利用して、OSを作るのに利用したりするものだ。
我々は、CPUの暴走は、その様なハードウエアによってだけ対処できない訳では無い。
対処する方法は、ソフトウエアにNOP命令を埋め込んで利用する方法論が考えられる。
 ハードウエアの異常時には、CPUのインストラクション解析する部分、または、PC(プログラムカウンター)が異常なコードを解析してしまう事があると仮定してみよう。
そういう壊れたインストラクション解析する場合、それを正常にもどすには、何もプログラムを実行しないNOP命令を連続的に多用して使えば、CPUが正常に戻った時、NOP命令を実行し続けて、CPUの異常暴走をくい止める事ができるだろうと仮定してみる。
更に、異常時対処するためのNOP命令のグループを実行した後、どこかのエラー処理にジャンプして適切な異常処理を実行した後、また、元のプログラムを実行してもらうか、もしくは、リセットからシステムを始める様にすれば、それは、CPUが暴走する時のエラーリカバリー処理となるだろう。
 この様に、NOP命令とは、不必要な命令ではない。
エラー処理、フェルセーフ、フォールトトレランスなる処理をする時、NOP命令が何もしない命令だからこそ有効に使えるアセンブラ命令としての使い道があるものである。
 その他、CPUが暴走する場合でも、そのエラー対策を行えるソフトウエアについて考えてみる。
作ったソフトウエアにどこまで動いたかを記述するチェック・ポインター領域を設ける事が考えられる。(チェック・ポインター領域には、どこまでプログラムを実行しているか?その時のメモリー内容やCPUのレジスター内容をメモリーに記述する。)
CPUが異常な動作をしたら、とりあえずエラー処理にPC(プログラム・カウンター)にジャンプ先を設定して、今まで、どこまで処理を進めてきたのかだとか、その時のCPUのレジスターやメモリー内容はどうであったかだとかをプログラムがチェック・ポインターを通過して実行した時点で記述したメモリー内容やCPUのレジスター内容を復旧させて、問題無くプログラムを再開させるための工夫をしてゆく事が考えられるだろう。
 現在は、もっと複雑な事象に対応するエラープログラムというのがあるかもしれないが、
信頼性のあるソフトウエア開発の基礎とは、以上の事が考慮されていると考えられる。




アセンブラでのプログラム設計作法。(2/2)著者:吉田作太郎

10.ポートからの値の入力に関して。

 システム開発時には、ポートからデーターをREAD(入力)する場合、一度読みで作っても良いが、本番用では、それでは許されないものである。
それは、入力するデーターがふらついて、正しい値でない場合が考えられる。
そこで、次の方法が考えられている。

10.1.データーの三度読み。(多数決理論)

 ポートのデーターを三度読み、ポートの各ビットの値が、二回以上ONならONと判断し、二回以上OFFならOFFだと判断して、データーを設定する。
こういう仕様を渡されると、できの悪いソフトウエア技術者は、拒否するか、この仕様を満たすためにポートからREADした各ビットを一つずつカウントしそれをいちいち数値の大小で判断するというとても長いプログラムを作ったりする。例えば8ビットのポートデーターを三度読みの多数決データーを作るのに、1ビットの判定用のプログラムを8個重ねてプログラムを作るのでとても遅くて長いプログラムを作ってこられたりするのでへきへきとさせられるものである。
この仕様を満足させるためには、集合論を使えば簡単である。
ベン図で、一回目の円、二回目の円、三回目の円を書いてみる。
この仕様を満たすのは、一回目の円、二回目の円、三回目の円が交わって部分を考えてみると良い。

図省略


すると、いちいち、各ビットを見て、ONとOFFを判断するプログラムを書くのではなく、「 ( 一回目のREAD ∩ 二日目目のREAD ) ∪ ( 二回目のREAD ∩ 三日目目のREAD ) ∪ ( 三回目のREAD ∩ 一日目目のREAD ) 」という式を使って、ポートをREADした(読んだ)データーを処理しておけば良い。
一回目のREAD=A,二回目のREAD=B,三回目のREAD=Cとすると
データーの三度読みの多数決=(A・B)+(B・C)+(C・A)
= A・(B+C)+B・C
 ちなみに、マトリックスを使えば、この様に表現できる。


マトリックス省略

このマトリックスを使って式を組み上げれば、このデーターを三度読みしてデーターを決定する仕様を満たす事ができる。
一回目のREAD=A,二回目のREAD=B,三回目のREAD=Cとして、多数決の項で「1」の部分に注目してその総和が多数決の式となるので、それは次の様になる。
多数決=(NOT(A)・B・C)+(A・NOT(B)・C)+(A・B・NOT(C))
     +A・B・C
   = (NOT(A)・B・C)+A・B・C
+(A・NOT(B)・C)+A・B・C
+(A・B・NOT(C))+A・B・C
   = (B・C)+(A・C)+(A・B)
   = (A・B)+(B・C)+(C・A)=A・(B+C)+B・C

この様な、データーの三度読みして値を決定する問題を、「多数決理論」と呼ぶ。
データーの三度読みの多数決理論とは、ソフトウエア化するには実践的で使いやすいものであるから、現場では多用される事であろう。
ここで、データーの三度読みの仕様について、五度読みならば、もっと正確なデーターが出せるなどと言ったりする技術者がいたりするが、これは、いささか、現実的ではない。
この集合理論で使われる式の各項の部分は三つのポートのアンドであり、それをオアする項の数が次の様に計算される。
「コンビネーションの5の2(5C2)」もしくは、「コンビネーションの5の3(5C3)」で計算される項が必要な集合の式になってしまう。
すると、その値は、「5!/(2!・3!)=10項目」となる。
すると、計算する回数は、最大、「3*10=30回」なる計算が必要とされるだろう。
ポートをREADするには、そこまで手間暇かけて多数決理論を実践する必要は無いだろう。
ポートのREADに多数決理論を使うには、3で充分だと私は思う。


10.2.データーの二度読み。

 ポートのデーターを二度読み、同じ値ならばその値を設定し、違う値ならば以前の値を残しておくという仕様を満たす仕様について考えてみよう。
そのマトリックスは次の様になる。


マトリックス省略



元のデーター=A,一回目のREAD=B,二回目のREAD=Cとして、二度読みデーターの項で「1」の部分に注目してその総和が二度読みデーターの項の式となるので、それは次の様になる。
二度読みデーター=(NOT(A)・B・C)+(A・NOT(B)・C)
         +(A・B・NOT(C))+A・B・C
        = B・C+(A・(B.EOR.C))
これは、ソフトウエアによる簡易なチャタリング対策に使える仕様である。


10.3.チャタリング対策。

 チャタリング対策とは、スイッチの入力のON/OFFに関する問題対策である。
スイッチのON/OFFをすると、すぐにONやOFFにならないで、一定時間ON/OFFをふらついて、その後、やっとONやOFFした値になってくれるものである。
人間の目で見たら、そういう現象が無さそうであるが、コンピューターでスイッチのON/OFFの状態を見ると、スイッチは、1~100ミリSEC(秒)の間に、何度もONとOFFの間をふらついていたりするものである。
これが、チャタリングというものである。
チャタリング対策は、ハードウェアによる対策と、ソフトウエアによる対策が考えられる。
(ハードウェア対策1)
RSフリップフロップを使う。
(ハードウェア対策2)
ポートの入力端子に、ヒステリシス特性の有るシュミットトリガーというゲートICをまず使う事。
この入力端子に、コンデンサーと抵抗と電源ラインを上手に接続させて(決まり切ったパターンであるが)、入力端子を作ると、ノイズの影響を受けにくい入力端子となるのである。
(ソフトウエア対策)
一定時間間隔(例えば1~100ミリSEC(秒)の間隔)で、入力端子の値をポートからREADして、同じ値が続いたら、その値になったと断定して、ONになったとか、OFFになったとかをソフトウエアによって決定する。これは、使われる機器によって仕様も違うし、また、各会社によっても、やり方が違うものである。
相手の会社の技術者に聞いて、どの様な仕様で、ポートの値を決定するかを聞いて、そのソフトウエアを作る事。


11.開発に必要なハードウェア資料。

 ソフトウエア開発において必要なハードウェア情報とは、まず、「ハードウェア構成図」と「メモリーマップ」と「I/Oに使われている部品の説明書」である。
また、ハードウェアの事を良く知っているソフトウエア開発者のためには、ハードウェアの回路図を示してくれれば良いだろう。


11.1.ハードウェア回路図。

 回路図の事である。


11.2.ハードウェア構成図。

 CPUのバスに、どのハードウェアが接続されているか示す図の事である。
CPUのバスには、データーバス。アドレスバス。コントロールバスがある。
一般に、この3つのバスを一つのバスとして表現し、各I/Oの部品の表現はどの様に接続されているかを示して表現する。
ここで、I/O部品とデーターバスの間に書かれている矢印は、データーバスからのデーターの流れを示しており、出力なのか?入力なのか?入出力なのか?を矢印で示しておく事になっている。
 このバス表現は、場合により、アドレスバスとデーターバスの2種類が表現されている図もある。
この場合、アドレスバスを解読して各I/Oへチップセレクト(CS)線を出して、各I/Oを制御している事を示して表現している場合もある。


11.3.I/Oに使われている部品の説明書。

部品の製造会社から発行されているマニュアルを使う。
各部品が、どの様に制御すれば、何がどうなるかを示す資料である。


11.4.CPU情報。

 機械語をアセンブラにして言い表した命令の一覧表が、まず、必要である。
それは、どんな命令があるかを知るために必要である。
次に、割り込み情報が必要である。
割り込みが発生した時、どこにプログラムがジャンプするかという仕組みを知り、割り込みが発生した時の対策を考えてプログラムを作る事ができなければならない。
また、CPUに内蔵されている各I/O情報も知り、作るシステムの仕様に合わせてプログラム作りができなければならない。


11.5.メモリーマップ。

 どのアドレスに、何のハードウェアが配置してリード・ライトしているかを説明している図の事である。
また、どのアドレスにROMやRAMがあるかの情報が必要である。
RAMの情報で必要なのは、どこにスタックポインターを定めるか決定するために必要である。
RAMに関して、その他は、利用できるRAM領域を知るために必要である。
また、ROMの情報で必要なのは、どこのアドレスがプログラム開始領域であるかという事を知り、プログラム領域がアドレスの何番地から始まるかというオリジン(ORG)を定める時に必要である。
また、プログラムサイズを元に、どこまでプログラムが書けるかという利用できるROM領域を知るために必要である。
また、ROM領域は、リセット割り込み、NMI(ノンマスカブル・インターラプト)、各インターラプトのジャンプアドレスの書き込みに必要である。
これには、CPUの情報を知る必要がある。


12.開発時に作成しなければならないソフトウエア資料。

 プログラマーは、ソフトウエアドキュメント(資料)として、最低限、次の資料を詳細設計時、書いて、ドキュメント資料として残しておかなければならない。
※ これは、基本設計の資料作成の事ではない。あくまで、詳細設計の資料である。

1.基本設計がある場合は、基本設計書。
2.サブルーチン仕様書。(詳細設計)
3.サブルーチン仕様書に書かれている内容を実現させるためのフロチャート。(詳細設計)
4.モジュール構成図。
5.変数領域(メモリー領域)の資料。
6.ソース・プログラム・リスト。


図省略。


13.システム全体の設計手法。

 システム全体を設計する事とは、設計するシステムをいろいろな視点で見て分割できる様にする事である。
プロの設計は、設計したものを自分一人で作成するものではなく、複数の人間を雇って仕事を進める。
その場合、複数の人間にそれぞれシステムを分割した部分を作成してもらって、全体の仕事を成し遂げる。
すると、多くの人間で作成するとシステム全体の作業の時間が短縮される。
そのためのシステム全体の設計手法である。
すると、分割された各仕事をそれぞれの担当者にまかせて、それぞれの人間に納期を定めて仕事をさせて、いつまでに仕事を終わらせる事ができるかの目途も立つ。
その他、全体のシステムがどの様になっているかを検討するためにもシステム全体の設計手法は役に立つ。


13.1.データーとプログラムを分離する事。

 プログラミングのみで全てを記述してはならない。
例えば、インターネットでのHTMLの場合もそうである。
インターネットのブラウザはHTMLに合わせて画面変更できる様にプログラミングする。
また、データーを担当する人間は、HTMLに従ってデーターを記述する様にする。
これによって、画面設計とプログラミングの設計との分業が成される様になる。
また、パルスモーターの回転の場合、一回転させるためのポートの値は、一回転分のポートの値を別途データーとして持っておき、仕様変更の時、いつでもデーターを変更すれば修正可能になる様に作っておく事。
また、回転を徐々に上げたり下げたりする場合、そのモーターを回転させるためのタイミングを作るタイマー割り込みの値をデーター化してテーブルに登録する事。
すると、プログラムの事を知らない人間にそのテーブルの事を教えれば、いつでも、そのテーブルを変更すれば、モーターの回転のタイミングを変える事ができるので、実験で何度も値を変更して最適な値を選ばせる事を他の人間にまかせる事ができる。

13.2.シングルタスクの場合の設計。

 作るシステムの仕様を決定し、そのシステム全体の大まかな処理の流れを記述し機能分割をして必要なサブルーチンを定め、処理全体を設計する。
この時、同時に、メモリーの内容を設計する。
このメモリー内容の設計に関しては、特に、最初の頃にやる設計に関しては、サブルーチン間の通信に利用するバッファーの内容を設計して記述する事が重要である。
このバッファーとはオブジェクト指向設計においては一つのオブジェクトとなりうるものに相当する。
その後、詳細設計になってゆく時、最初の設計で設定したメモリー内容の他に詳細なメモリー内容を追加して設計をしておく事。
それは、バッファー内容の詳細なデーターや、それぞれのサブルーチンが使うワークデーターを定めて設計してゆく事になる。


13.3.RTOSを用いたシステムの基本設計。

 並列処理を必要としないシングルタスクのシステムを設計する事とは、プロセス中心の設計で充分であった。
ここで、急に、並列処理を行えるシステムを設計せよと言われても、ばらばらに各プロセスが動いて成り立っているシステム設計などは作りようが無い。
そこで、本格的な並列処理を用いた設計をしようとしたら、各プロセスにチームワークが整った思想の有る設計作法が必要となってくる。
それには、各プロセスを一つのデーターで起動させ順次各プロセスを実行するというデーター中心に物事を考えるという設計作法が考えられた。
それが、DFD(データーフローダイアグラム)による設計である。
 ここでは、RTOSを用いたDFD(データーフローダイアグラム)による基本設計の仕方について説明する。
DFDは、オブジェクト指向設計においてはアクティビティー図やシーケンス図に相当する。

(1) システムをDFDにて記述する事。
(2) システムは、複数のDFDのセッションに分かれる。
(3) 一つ一つのDFDのセッションの各処理は、一つずつタスクにしておく。
(4) 一つ一つのタスクは、DFD内の一セッションの順番通りにタスク間通信して接続させ、一つのセッションを完成させてゆく。
(5) そうやって、一つ一つのDFDの各セッションを完成させ全体の設計をしておく。
(6) セッションの違う各タスクに資源の競合が起これば、その部分にデッドロックと優先順位の逆転現象が起こらない様なパターンにして排他制御を入れておく事。(オブジェクト指向設計において、セッションが違う同一資源を取り扱う各タスクは、同一オブジェクトとして取り扱い、優先順位の逆転現象が起こらない様に配慮して、排他制御の処置をほどこす事。この同一資源を取り扱うための複数のタスクで構成されている一つのオブジェクトのオブジェクト内にある各タスクの排他制御のグローバル変数は、このオブジェクト内の属性として取り扱う事。)
(7) デッドロックが発生するパターンがあるらしい。複雑なタスクの流れ図を書いたら、どういう時、デッドロックが発生するかという事を事前に発見するためにそれを検証するシミュレーション・ソフトを使う事。
(8) DFDとは、会社の業務フローを書くのと似ている。


13.4.DFDによる設計と各タスクの起動イメージ。

 さて、DFDによる設計においてタスク間通信のイメージとは次の通りである。
まず、全てのタスクは、WAITして停止している事をイメージする。
そして、何かイベントが有った時、そのイベントによって一セッションのDFDが起動する事となる。
起動したDFD内の一セッションの各タスクは、DFDの一セッションの順番通りに起動する。それは、今までWAIT状態であったタスクがRAN状態となって自分の仕事をし、次のWAIT状態のタスクをタスク間通信を通してトランザクションデーターを与えながらRAN状態にして順次起動させるのである。
この様にして、タスク間通信の連鎖反応を通して、RAN状態になった各タスクは自分の仕事をしたら次のタスクをRAN状態にさせた後、自タスクをまたWAIT状態にして、次のタスク間通信が来る事を待つ様な仕組みにして設計するのである。

13.5.モジュール間通信。

さて、RTOSを使わないマルチタスクのシステムに関して言えば、トランザクションデーターをあまり用いる事をせず、モジュール間通信のバッファーを上手く活用する事によってシステム設計している事が多い。
しかし、RTOSを使った設計となると、同時間に各モジュールが処理を実行する事ができる並列処理を成り立たせるために、エンティティーとなっているトランザクションデーターがどうしても必要となってくるのである。


13.6.トランザクションデーターとは何か?

疑似並列処理を実現したマルチタスクを利用した設計において、一つのイベントが発生した時、一セッションのタスク間通信でシステムの動きを設計するという方法論がある。
その一セッションの処理を実行している時、複数のタスク間の間を流れる一つのワークバッファーとなる一連のデーター(構造体の形をしたデーターになっている)の事をトランザクションデーターと呼ぶ。
このトランザクションデーターは、並列処理になってくると設計に活用される重要度が増し、並列処理実行中に一つのイベントが発生した時、各タスク間を流れてプロセス同士に命令をつなげる役目を果たすためのタスク間通信に使われるものである。


13.7.イベントフラグを用いたタスク間通信例。

省略


13.8.オブジェクト指向を使った部品化についての例。

省略


14.OS無しでCPUを動かす方法。(CPUの初期処理方法について)

 まず、OS無しでコンピューターのソフトウエアを動かす場合、何が必要か考えてみよう。
(1) リセット割り込みで始まるプログラムの起動場所(起動アドレス)の設定。
(2) インターラプト(割り込み)のマスク(割り込みが起こらない様にする)。
(3) サブルーチンが使えるために、スタックポインターを設定する事。
以上の事がまず肝要である。
つまり、コンピューターの初期処理にはこの二つの事ができなければならない。
この問題の解決手段は次の通りである。

(1) まず、CPUのハードウエア・マニュアルを参照し、CPUの割り込み処理の項目を見て、リセット割り込みは、「CPUのアドレスのどこから始まるか?」または、「CPUのどこのアドレスにプログラム開始のアドレスを記入すれば良いか?(CPUの割り込みベクターの内容を調べてリセット割り込みの割り込みベクターにプログラム開始のアドレスを記入すれば良い。)」を調べてプログラム開発する事。
(2) インターラプトのマスク。つまり、CPUのインターラプトというプログラム・ジャンプ処理を禁止する事。これは、CPUのフラグレジスターのインターラプト・フラグをセットすれば良い。ここで言える事は、ハードウェア設計において、NMI(ノン・マスカブル・インターラプト)という割り込みの使用は、できるだけ使わない様にした方が良い。その理由は、初期処理の時、NMIが発生した場合、割り込み禁止状態も受け付けないで、NMIを実行してしまうので、初期処理が完了しないままNMIを使う事は、初期処理が未完のまま、NMI処理を実行する事になるので、その様な事をできるだけ避けたいためである。
(3) スタックポインターとは、CPUのレジスターとなっている。CPUのスタックポインターのレジスターの値をアセンブラで設定すればこの問題は解決できる。
以上の事柄は、CPUの初期処理の問題である。

では、実際、初期処理には、何が必要かについて考えてみよう。
○ インターラプトが発生しない様にする。(セットインターラプト)
○ ROMチェック。
○ RAMチェック。
○ スタックポインターの設定。
○ I/Oの初期処理。
○ メイン処理に入る前に、インターラプトを受け付けできる様にする。(クリアインタラプト)
以上である。
スタックポインターの設定は、ROMチェック、RAMチェックを終了してから設定する事。
その理由とは、プログラムのデーターのチェックをROMチェックで行い、スタックポインターを動かすメモリー領域のチェックのためにRAMチェックをするのである。
ROMチェック、RAMチェックをする前まででは、スタックポインターの設定をしてはいけないので、サブルーチンコールはできない。
だから、ROMチェックサブルーチン、RAMチェックサブルーチンは作らない。
その代り、CPUの初期処理には、ROMチェック部分を記述して、その次にRAMチェック部分を記述してからスタックポインターの設定をする様にしておく事。


14.1.ROMチェック。

 さて、ROMチェックについて。
プログラムの入っているROMにチェック・ビットを作っておく事。
それは、ROMの全内容をEOR、または、ADD命令でチェック・ビットを作っておき、ROMチェックするROMの最後のアドレスにその値をあらかじめ設定する事。
CPUの初期処理のROMチェック部分は、チェックするROMの内容をEORかADDなどの演算を通してチェック・ビットの計算をして、ROMの最後のアドレスのチェック・ビットの値と一致するかを確かめてROMチェックする。
一致した時は、ROMチェック正常。
一致しない場合は、ROMチェック異常という判定ができる。
もし、異常の場合、ROMチェック異常終了の時の仕様を考えてその処理を実行する事。
それは、例えば、ブザーを鳴らすだとか、異常終了ランプを点灯させたりするなどの方法が考えられる。
さて、プログラム開発時とは、ROMは、何回も書き直してデバッグし修正し書き換えるので、ROMチェック処理をするとシステム開発の手間がかかりすぎる。
そのため、プログラム開発の時は、ROMチェックをする処理はしない方が良い。
プログラム開発完了時、ROMチェック処理はアクティブにしておく事。
また、プロラム開発終了時でも、後で、障害が分かった場合、ハンドアセンブルしてROMの内容を書き換えてプログラム修正する事がある。
その時、ROMチェック処理がじゃまな場合が多いのでROMチェック処理は非アクティブにしておく事。
そのために、ROMチェック処理をアクティブにするかしないかを決定する部分をROMの中のどこのアドレスのビットに設定するかを決めておく事。


14.2.RAMチェック。

 次に、RAMチェックは、RAMにビットパターンを書き込んで、その書き込んだビットパターンを読み直した時、RAMに書いたビットパターンと一致しているかどうかを判定してRAMチェックする事。
RAMチェックするためのビットパターンとは、プログラム開発する会社によって、その考え方が違っているので、その作法も千差万別である。

その一つとして、4種類のパターンでRAMチェックするのがある。
それは、全ビットが、全て“1”を設定した後チェックし、その後に、“010101・・・”というビットパターンを設定してチェックし、その後に、“101010・・・”というビットパターンを設定してチェックし、その後、全て“0”を設定してチェックするという方法論である。
また、RAMチェックする時、RAMにアクセスするアドレスをインデックスレジスターに設定し、アクセスするRAMのアドレスのメモリーの内容をインデックスレジスターの値を特殊な計算で設定しておいて書き込み、後で、そのRAMに書き込んだ内容が正しいかをチェックするRAMチェックがあったりする。
インデックスレジスターの値を特殊な計算をするというのは、例えば、RAMデーターが8ビットでアドレスバスが16ビットの場合、インデックスレジスターは16ビットとなるのだが、その16ビットの上位8ビットと下位8ビットを加算してその値をRAMチェックのビットパターンとするというものである。
前者の4つのビットパターンを用意してRAMチェックするという考えとは、“1”と“0”の全ビットパターンをチェックするという考えである。
後者のインデックスレジスターを用いてRAMチェックするという考えとは、RAMのデーターがゴースト状態になっている時、前者のRAMチェックではゴーストが見破れないので、見破るために、この様なチェック方法が考えられているのである。

RAMというメモリーのゴーストとは何か?
一つのメモリーが壊れて、別のアドレスに書き込んだメモリー内容がそのメモリーの全内容になってしまうという事が考えられる。
また、二つのメモリーICがあって、ハードウェアのチップセレクトの信号の配線が異常の場合、一つのメモリーICが配線され、一つのメモリーICが無接続ではあるが、アクティブなメモリーICがあたかももう一つのメモリーICがあるかの様に動く場合がある。
これは、あくまでも、配線の問題であるが・・・・
この場合、存在しなくても、ゴーストとして存在しているかの様に振る舞っている。
これが、ゴーストというものである。
そのチェックの方法は、インデックスレジスターを利用した方法もあるが、前者の方法をいろいろと改善してチェックする方法もあるのでここで少し解説しておこう。
例えば、1ワードずつ4つのビットパターンをチェックして全RAMをチェックする。
また、連続したnワードずつ4つのビットパターンをチェックして全RAMをチェックする方法などが考えられる。
 RAMチェックは、いろんな方法がある。
各会社にとって、その作法は、違っているので、開発する場合、その会社の作法に合ったRAMチェックをする事。

 さて、現在、RAMは、MMUによって管理されているものである。
このMMUによって、パソコンは、物理アドレスが連続に配置されていないRAMを連続したかの様に使いこなす事ができる様にするものである。
パソコンなどのコンピューターは、連続していないRAMがMMUで管理する前に、RAMがどの様に配置されているかを確認する必要がある。
この確認の方法が、また、RAMチェックを応用しているのである。
RAMチェックして、コンピューターにRAMが、どの様な容量のRAMが何枚有り、どの様にMMUに配置しているかを確認し、その後、RAMのヘルスチェックするために新たにRAMチェックするのである。
こういうのは、普通、OSの無いコンピューターではやらず、OSの有るコンピューターで処理するものだから、プログラマーはあまり考える必要は無いかもしれないが、原理ぐらいは説明するために、ここに記述しておく事にした。


14.3.スタックポインターの設定。

 次に、スタックポインターの設定に関して。
これは、別段、どのコンピューターでも同じであろう。
CPUのスタックポインターのレジスターの内容を設定すれば良いだけの事である。
ただ、コンピューターにとって、メモリーとは2種類のものがあったりする。
それは、システムに確かに存在するスタティックRAMエリアと、コンピューターの初期処理を終了して広いメモリエリアを活用するDRAMエリアがあるというものだろう。
この場合、第1回のスタックエリアの設定のために、スタティックRAMにスタックポインターを設定してDRAMをチェックし、DRAMエリアが有効であると分かると、そのDRAMエリアにスタックポインターを設定するという事もある。
また、マルチタスクOSの内部は、各タスクへディスパッチする場合、常にスタックポインターを各タスク用に書き換えているものである。
だから、スタックポインターの設定というのはシステム開発の場合は考慮しなければならないが、それ以外のアプリケーション開発には意識する必要が無いものである。

 次にスタックのサイズについての検討であるが、アセンブラの場合は、サブルーチンコールの深さとスタック操作命令を計算して出す事ができるだろう。しかし、これには時間がかかるのが難点である。C言語の場合は、関数呼び出しがサブルーチンコールと同様にスタックを消費するが、その他にも、アーギュメント(引数(ひきすう))とローカル変数のエリア分がスタックを利用している。これらを計算する事ができるというのならば、スタックサイズの検討をする事ができる。こういうのは、コンパイラーにスタックサイズを計測するツールがあるかもしれない。更に、スタックサイズの検討には、割り込み部分のスタックの余裕も付けてスタックサイズを決定する事。


14.4.I/Oの初期処理。

 次に、I/Oの初期処理に関して。
スタックポインターが設定してある時にチェックするので、各サブルーチンを用意してチェックすれば良いだろう。


14.5.メイン処理へ。

 これら初期処理が終われば、今度は、メイン処理である。
メイン処理とは、通常のシステム設計の領域であり、通常運転のプログラムを書けば良い。
これにて、コンピューターの初期処理に関する一般論の説明を終える。


15.アイデアを出す事について。

顧客にアイデアを提案すると喜ばれるという常識らしきものがある。
しかし、それが、顧客の喜ぶものと嫌がられるものがある。
○ 喜ばれるもの。
自分が率先して仕事をして、顧客と同じ苦労をし、今、自分が悩んでいる話を顧客にする場合。(顧客は、よくぞ聞いてくれたと思って喜び、相談に乗ってくれ、しかも解決策を出そうとしてくれる。)
また、顧客の問題点を見つける事、その原因を追及する事、その解決策を示す事。
それらをレポートに書いて顧客に提出する事ができたら、顧客は喜ぶ。
○ 嫌われるもの。
何も顧客の苦労について分からないまま、思いつきのアイデアしか出さない場合。
その場合、顧客は、そのアイデアを採用しても、アドバイスを与えないし、もし、失敗しても、援護をしてくれない。請負仕事の場合、これは、致命的な欠点となる。
つまり、嫌われる事とは、お客様に好かれようと、思い付きのアイデアを出し続ける事が、とてもお客様に迷惑である事になってしまうのである。
仕事をして必要にせまられてアイデアを出す人間は、逆にお客様に好かれる事となる。


16.窓口の一本化と議事録の作成。

 組織論として、プロジェクトを作ったならば、お客様と交渉を担当する窓口を一つとしなければならない。
この窓口は、即決で、お客様からの仕様変更に関する要望を簡単に受け入れてしまっては困る。
お客様とのコミュニケーションを元に、仕事を担当する各部署に連絡を取り、お客様からの要望が実現可能かということを相談し検討してもらって、その意見をプロジェクトの窓口を通してお客様に伝える役目を持つ。
また、仕事の担当者からの質問や意見に関して、この窓口を連絡係として通して伝え、お客様の意見を基に互いに知恵を出し合うコミュニケーションなどが始まる。
そして、この仕事上の仕様変更を含めた契約に関するコミュニケーションの全内容を議事録として記録する事が肝要である。
記録した議事録は、項目ごとに分類して記録してはいけない。
全部、一つのバインダーに、時間順に、メモして記録すること。
その理由は、分類という作業をした後、その情報が欲しいと思っても、なかなか見つからないものである。
それならば、時間順に記録していた契約に関する資料があると、自分自身も良く覚えていて、早く、簡単に、その議事内容にアクセスすることができるためだ。
また、その議事録は、相手が言った事を確認するために、お客様からの印鑑を押したりサインをお願いしたりすることも大事だ。
プロジェクトに、そういう窓口があると、お客様と自社との間で、言った、言わないという交渉のトラブルを無くす事ができる。
そのトラブルが無くなる理由とは、交渉の窓口が、そういう事を一元管理して約束事を記録しているためだからである。
 議事録の議決内容とは何か?
それは、ほぼ、契約に近いものであり、お客様からの絶対命令に近いものである。
もし、ここで、プロジェクト内のメンバーが、ばらばらにお客様からの要望を受け付けてしまったら、仕事の納期の関係だとか、実現すべき機能に対して、約束が守れない状態になってしまう場合が多いのである。
お客様とプロジェクトにおいて、窓口の一元化とその窓口での議事録を一元管理していない職場では、問題が発生した時、誰がどこを担当して仕事をして交渉したか分からないので、仕事が複雑になってくると、責任問題があいまいになり、誰が悪いのかを管理できなくなり、責任の所在が分からなくなり、そのため、そこで発生する多くのトラブルによってお客様から見限られ仕事を失敗してしまう可能性が高くなってしまうのである。
後、この窓口の役割を担当する者としては、絶対、顧客に対して守れない様な約束をしてはならない。責任を持って約束を守れるかどうかを判断できる人間が担当しなければならない。であるから、顧客から出た案は、すぐその場では絶対的な案では無く、自分の仲間への報告資料として書き、担当部署へ連絡して、その後、顧客と担当部署の人間が相談して合議をするなる約束事が必要である(報連相)。コミュニケーションには手順が必要なのである。そして、この顧客との相談においては、簡単にできない様であるならば、顧客から知恵を拝借したり納期を延長してもらったり人員を増やしてもらったりするというコミュニケーションができなければならない。そして、相談を通して約束事を決めるのである。そして、担当部署は、その責任を果たすために仕事をするのである。

アセンブラでのプログラム設計作法。(1/2)著者:吉田作太郎

注意事項:
 これは、プロ用のアセンブラの設計作法である。
これは、私独自のソフトウエアの生産技術である。
各メーカーごとには、独自の生産技術があるので、この生産技術がどこへでも役立つというものではない。
もし、あなたが、一人前の技術者として雇われても、自分の持っている技術とは別物の研究された独自の技術を相手会社が持っている事がある事を忘れてはならない。
この場合、自己主張して、「私には独自の技術があるから大丈夫ですよ。」なる事を言ったら、自殺行為である場合がある。
各メーカーの職場には、それぞれの独自技術、そして、独自の作法、そして専門用語があるものである。更に言うならば製品化の技術も備えており、そのためにはウォーターフォール型の開発手法以外の独自の開発方法論も備えていたりする。そういう事を心得て相手を尊重し尊敬する態度で仕事に接する事。
派遣社員は、それを心得て、仕事をおぼえながら適切なコミュニケーションをしてお客様に喜ばれる仕事をする事。
また、請負業者、受託業者なるのも、孫請け、ひ孫請けによって契約されていたとしても、自分達の独自技術で仕事をすると失敗する可能性が高い事を心得た方が良いだろう。
仕事に成功する可能性を高くするには、元請けの会社の生産技術である、仕事の作法と用語をまず一致させねばならない。
それが、できねば、まともな仕事をする事ができない事を心得た方が良いだろう。
なぜ、請負業、受託業務の孫請け、ひ孫請けの形態が仕事を失敗させる可能性が高いか。
下請けの会社に対して元請けの会社が与えたソフトウエアの生産技術を元に仕事をしてもらいたいと願っている場合、というよりは、そうでなければ生産できない仕事があったとしよう。
その下請けの会社が金に目がくらんで、別の会社へ仕事を依頼するが、仕事の元請けの生産技術を教えないで仕事を与えるケースがほとんどなのである。
そういう仕事は、必ず失敗するものである。
この様に、孫請け、ひ孫請けの業務とは、モラル違反している場合が多く、考えられない失敗をしでかす事が多いものなのである。
元々、この業界はモラル違反して仕事をしている事が多いので、そのため失敗する可能性が高くなっているので、成功させるためには、この原因を取り除いて仕事をせねばならない。
そのためには、仕事元とコンタクトして、プログラミングの生産技術に関して教えを請う事が肝要となる。
世の中で、仕事が失敗する理由とは、技術力の差ではない。本質的問題は、その根深い問題はモラル違反である場合が、ほとんどなのである。
それは、長年、受託請負業をやってきた私の感想である。

記述目的:
(組織力を活用したプログラミング中に発生する間違の発生率の減少)まずは、間違い率の少なくなる様な工夫をしているプログラミングの設計作法を考え出し、それをチーム全体に普及させながら、ある程度のプログラミングの設計作法を統一させる事によって、設計作法の異なるプロのプログラマーを集めて仕事をさせても間違い率の少ない同一品質のプログラムを作り出させる。それはプログラミングの設計作法をパターン化する事になり、プログラミング中に発生する間違いの発生率”の減少をさせる事ができ、それに加えて個人とチーム間のコミュニケーションが活性化しやすくなり、組織内の会議的コミュニケーションが活性化しやすくなるので、お互いの受け持つ仕事内容が干渉しやすくなり、お互いの受け持っている仕事の内容を互いに理解し合う事ができる仕組みを作りやすくさせる事になる。そして、それによってプロジェクト内に組織力を作り出しチームワークを発生させる事によって、“プログラム設計の仕様内容に関する問題点を互いに指摘し合う環境を作る事になり、それによって開発するシステム全体の問題点を次々と解決させてゆける環境を作ってゆけるようになるのである。この様に、この文章の記述の最終目的とは、そうやって強い組織力の有るプロジェクト及びチームを作ってゆき、品質の良いシステム開発してゆく事である。

対  象:
 それなりの個人的な技術力を持っているプロのプログラマーのため。

記述方針:
 あらゆるアセンブルを活用するプログラミングに対応できる簡単なガイドラインとなるように記述する。

効  果:
 処理内容を理解しなくてもパターン化に注目した机上デバッグを一人でするだけでも間違い率を減少させる効果がある。もし、これを集団で机上デバッグ作業も含めたプログラム開発したとしたら、個人の知によるプログラム開発ではなく集団知という組織力を生み出す開発体系の有るプログラム開発のプロジェクトを作りやすくさせるので、その効果は計り知れないものとなる。

注意事項:
 これは、アセンブラというプログラム言語を学習する人のために書かれてはいない。あくまでも、アセンブラの基礎知識があるプロ用である。もし、アセンブラのプログラム言語を学習し技術を習得したい人がいるならば、これとは別の本を読んで学習する事。


目次

1.プログラマーはなぜサブルーチン化したがるか?
2.アセンブラでのサブルーチン設計の仕様書の作成項目。
3.フロチャートの書き方。
3.1.アセンブラの分岐とスッタク操作命令(PUSH/POP)の在り方の検討。
3.2.サブルーチンの記述。(コーディング規則)
3.3.プログラムリストで見るアセンブラと高級言語との比較。
3.4.モジュール構成図を用いての検討。
3.5.ループ処理の奥義。
3.6.ビッグNUMにおける計算。
4.分岐命令で使われる数値表現の統一。
5.インターラプト・フラグのマスクの作法について。
6.ジャンプ先のアドレスの書き換えの禁止。
7.状態遷移図がある場合の分岐の書き方。
8.データーをテーブル化する事。
9.ポートの入出力のON/OFFに関して。
10.ポートからの値の入力に関して。
10.1.データーの三度読み。(多数決理論)
10.2.データーの二度読み。
10.3.チャタリング対策。
11.開発に必要なハードウェア資料。
11.1.ハードウェア回路図。
11.2.ハードウェア構成図。
11.3.I/Oに使われている部品の説明書。
11.4.CPU情報。
11.5.メモリーマップ。
12.開発時に作成しなければならないソフトウエア資料。
13.システム全体の設計手法。
13.1.データーとプログラムを分離する事。
13.2.シングルタスクの場合の設計。
13.3.RTOSを用いたシステムの基本設計。
13.4.DFDによる設計と各タスクの起動イメージ。
13.5.モジュール間通信。
13.6.トランザクションデーターとは何か?
13.7.イベントフラグを用いたタスク間通信例。
13.8.オブジェクト指向を使った部品化についての例。
14.OS無しでCPUを動かす方法。(CPUの初期処理方法について)
14.1.ROMチェック。
14.2.RAMチェック。
14.3.スタックポインターの設定。
14.4.I/Oの初期処理。
14.5.メイン処理へ。
15.アイデアを出す事について。
16.窓口の一本化と議事録の作成。
17.コミュニケーション。
18.契約。その1。
19.契約。その2。
20.仕事をする態度。


1.プログラマーはなぜサブルーチン化したがるか?

 モジュール構成図に処理の機能を記述したいからである。
重複する処理がある場合、サブルーチン化するものであるが、大きな処理がある場合、機能単位にサブルーチンを作る事により、モジュール構成図を見ても処理の内容が分かるドキュメントを作りたいがためにサブルーチン化する事が多い。


2.アセンブラでのサブルーチン設計の仕様書の作成項目。

 アセンブラでサブルーチンの仕様書の書き方とは
(1) サブルーチン名の記述。
(2) 処理内容の記述。
(3) 入力データーの記述。
(4) 出力データーの記述。
の項目が必要である。
入力データーとは、CPUのレジスターが中心であり、メモリーである事もある。
出力データーとは、CPUのレジスターとメモリーの他に、CPUのフラグレジスターの内容も記述する。
入出力データーのメモリーの内容については、直接アドレスを指定したメモリー内容(直接アドレッシング)であったり、指定したレジスターや指定されたメモリーからのポインターが示すメモリーの内容(間接アドレッシング)であったりする。
また、出力データーのCPUのフラグレジスターの内容とは、キャリーフラグ(C)、ヴォローフラグ(V)、ゼロフラグ(Z)であったりする。
例えば、サブルーチンの設計の処理内容述を、正常終了の時はキャリーフラグを0、異常終了の時は1をセットするなる事を定めて記述しておく様にしておくのである。
アセンブラにはフラグレジスターの内容によって条件分岐する事ができる命令があるので、サブルーチンのコール元が、サブルーチンをコールした後、次に何の処理をさせるべきかを判断するために、サブルーチンコールで出力されてくるフラグレジスターの内容を頼りとする設計にする事がアセンブラを活用するプログラミングにとってやりやすいのである。

3.フロチャートの書き方。

 アセンブラのプログラミングは、プログラミングーリストを見てわかるとおり、構造化プログラミングが、不可能であるかの様だ。
ここで、設計段階に於いて、フロチャートによる検討を行なってから、プログラミングをせねばならない。
この時、構造化プログラミングの技法と独自のパターン化を決めて、フロチャート上、設計してゆく。
その作法を以下に示す。


3.1.アセンブラの分岐とスッタク操作命令(PUSH/POP)の在り方の検討。

(1)出来るだけ分岐の少ないプログラムを作る。
CPUのパイプライン処理の効率を考えると、その視点に於いても理にかなう。
(2)フロチャート上、一点で分岐した処理同士は、必ず一点に戻る事。
分岐する直前と、分岐後の処理が、一点でまとまった部分を一つのブロックとして取り扱ってマクロ的に見ると、全体的に一つのまとまった処理とみなす事ができ、思考上、分岐のない形で、プログラム全体を見る事が可能である。このため、設計者は、1エントリー、1アウトプットを誇張して、各処理を設計するよう、こころがける。
(3)分岐命令の活用のパターンを次の様に統一する。
   ○ LOOP(1エントリー、1アウトプット)
   ○ 分岐       (  同  上   )
   ○ サブルーチンコール(  同  上   )
※ マルチエントリー、マルチリターン処理は、避けるのが奥義。(サブルーチンコールの場合で、もし、マルチエントリーが必要だと感じた場合、共通処理をサブルーチン化し、マルチエントリーとなっているラベルと同じ名前のサブルーチンをエントリー数分作り共通処理の部分のサブルーチンをコールするという形式を採用して、無理にでも1エントリー1リターンのサブルーチンを作る事にこころがける事。)
(4)スタック操作命令は、PUSH,POP(PUL)命令を中心に考える。
これは、CPUのレジスターを保持する時、活用する命令である。
設計時点で、これを活用する時、マクロ的に見て、1エントリー、1アウトプットとなる処理に於いて、エントリー部分にPUSH、アウトプット部分にPOP(PUL)する様にこころがける。すると、処理に必要とするレジスターの量を最大限に活用してプログラミングできる様になる。

※ (2)、(3)のパターンを徹底的にやる理由。
特に、分岐命令のプログラミングは、間違い率が高くなる部分である。だから、この様なプログラミング・スタイルにパターン化すれば、間違い率が少ないプログラミングができ、プログラミングミスがあれば他人にプログラムミスを指摘されやすくプログラミングする事ができる。
※ (2)、(3)、(4)のパターンを徹底的にやる理由。
スタックのメモリー内容は、必ずサブルーチンのコールやリターンのアドレスが入っている。その領域を使ってPUSH,POP(PUL)命令を使うのだから、PUSHした回数分、必ずPOP(PUL)してくれないと、リターンする時サブルーチンコールのアドレスが狂ってリターンする事になり、そうなると必ずプログラムが暴走する事となる。そういう暴走を阻止するために、(2)、(3)、(4)のパターンに当てはめて徹底的にプログラミングする事。すると、このパターンでプログラミングする事を知っているプログラマー達は、PUSHした回数分POP(PUL)しているかを見て、机上デバッグする事ができ、スタック操作命令によるミスによって暴走するプログラムを作成する事を事前に阻止する事ができる。

※ (2)、(3)、(4)のパターンを徹底的にやる時、構造化プログラミングであるC言語のIF文のコーディングルール同様に、段落分けしてコーディングする作法も勧められる。それは、間違い率の減少のためにやる作法である。ただ、これをやるかどうかは、各プロジェクトごとにコーディングルールを定めてやる事。
このルールに従ったソースリスト上の記述例は以下の通りである。
○ PUSHしたら、その行以降は一段落下げて記述する。
○ POP(PUL)したら、その行以降は一段落上げて記述する。
○ 条件文で分岐したら、その行以降は一段落下げて記述する。
○ 分岐して戻ったら、その行以降は一段落上げて記述する。
○ ループする構造になったら、その部分は一段落下げて記述する。
以上の記述例の場合、ソースリストの段落の上げ下げで分岐とループの処理内容のブロックが分り、スタック操作の間違いも段落の上下の違いがあるかどうかの判断で済むので分りやすくなる。

 この様な規則で、プログラムを設計すれば、内容を見ず、パターンだけ見るデバック方法の分野が開け、ミスチェックに効果がある。
これにより、他人に、ある程度のデバックを頼める事ができ、更に決まったパターンなので、なれると読みやすくなる。


3.2.サブルーチンの記述。(コーディング規則)

 サブルーチンは1エントリー、1アウトプットの構造だから、コーディングする時、プログラムリスト上、エントリーする部分は一番上であり、アウトプットする部分、つまりリターンする部分は一番下に記述する事。
分岐命令があっても、その処理は、その処理のリターンの後に記述してはならない。
また、サブルーチン内の分岐によって発生する1エントリー1アウトプットとなっているブロックは単にフロチャートの記述の順番どおりにコーディングする事。
ただし、特殊な例外として、もう、ROMになっているプログラムの内容を変更するためハンドアセンブルする時、ROMの空き領域に追加プログラムを記述する場合は規則にしばられない。


3.3.プログラムリストで見るアセンブラと高級言語との比較。

フォートラン、コボル、C言語などでは、アセンブラの条件分岐にかわる表現として、
(IF・・・THEN・・・・ELSE・・・・)が、ある。
コーディング時、処理内容についてこの段落分けをした表現を活用したプログラムリストを見ると、処理の内容が分かりやすい。(プログラムリストを読む場合、アセンブラの分岐命令は、各処理の視点が、他に移りやすいので、見にくいプログラムとなる。だが、高級言語は、条件による処理内容の変化を段落分けして表現するので、感覚的に分かりやすい。)
ところで、高級言語は、マルチエントリーが、できない様に出来ているが、マルチリターンが、可能となっている。
今までのプログラムの設計者は、マルチリターンは、良くない事となっていたが、これほど、理解しやすい高級言語上では、多くの過去の技術を知らないプログラマーの登場により、その方針が、退化して、マルチリターンを認めざるを得ないだろう。
また、マルチリターンも、なれてくるとなかなか使いやすい記述でもある。
だが、それでも、アセンブラのプログラミングにおいては、プログラマーの間違い率の軽減のためにスタック操作命令のパターン化を重視した構造化プログラミングを徹しマルチエントリーとマルチリターンのパターンのプログラミングを禁止しなければならない。


3.4.モジュール構成図を用いての検討。

 マルチエントリーのサブルーチンを書かれると、モジュール構成図を描く事はできない。
モジュール構成図が記述できるサブルーチンを書くためにも、サブルーチンのエントリーは一つでなければならない。
では、マルチエントリー化されたサブルーチンをどうやってシングルエントリーのサブルーチンに変えれば良いか?
それは、各エントリーごとにサブルーチンを作るのである。
そして、マルチエントリーでの共通部分になっているブロックを共通サブルーチンにして、各エントリーごとに分離したサブルーチンの共通処理のサブルーチンとするのである。
こうやって、マルチエントリーのサブルーチンをシングリエントリーにしてゆく。


3.5.ループ処理の奥義。

パターン化の手順その1。
(1)ループカウンターに使うレジスターにループ回数の数値を入れる。
    (2)ループカウンターをPUSH。
    (3)   ループ中の処理。
    (4)ループカウンターをPOP(PUL)
    (5)ループカウンターを“マイナス1”する。(デクリメント)
    (6)ループカウンターが0でないなら(2)へジャンプしてループする。
       ループカウンターが0ならばループから抜け次の処理へ。
    (7)ループの次の処理へ。
パターン化の手順その2。
(1)ループカウンターに使うレジスターにループ回数の数値を入れる。
    (2)ループカウンターをPUSH。
    (3)   ループ中の処理。
    (4)ループカウンターをPOP(PUL)
    (5)フラグレジスターを見て(3)のループ中の処理が中断を要求している場合(8)の処理へジャンプ。
    (6)ループカウンターを“マイナス1”する。(デクリメント)
    (7)ループカウンターが0でないなら(2)へジャンプしてループする。
       ループカウンターが0ならばループから抜け次の処理へ。
    (8)ループの次の処理へ。

※ ここで、ループをする処理においてループカウンターの判断を0かそれ以外かで判断する理由は、仕事がいそがしくなってくると、いちいち、+、0、-の条件を見てコーディングとデバッグしていると思考力を使い思考力を疲れさせるため間違いを起こしやすくなるので、0かそれ以外かの判断を使った方が作業が効率的になるという理由で活用するのである。
それは、また、別の表現で解説すると“>=”(以上)、“<=”(以下)、“>”(それより上)、“<”(それより下)の条件を使って判断してプログラミングしてゆく事よりも“=”(等しい)の条件で判断する方が間違い率が少なくなるという理由のためである。
※ パターン化の手順その2において、(3)のループ中の処理がエラーなどの理由でループを中断しなくてはならない場合には、(3)の処理は設計仕様においてはフラグレジスターのキャリーフラグなどを活用してエラー情報を出力するものであるが、その場合、ループカウンターのスタックをもどした後、判断するのがよく用いられるパターンとなるのでサンプルとして記述した。
※ 基本的にCPUのレジスターのPUSH,POP(PUL)に関してフラグレジスターの内容は変化しないという点に着目する事。
※ この様な作法でループカウンターに使うレジスターをスタックで記憶させておくと、ループのネスティングも同じCPUのレジスターをループカウンター用として活躍させる事ができる。(例:8086のCレジスター)


3.6.ビッグNUMにおける計算。

 ビッグNUMとは、CPUで計算するデーターレジスターの幅よりも大きな数値の事である。
例えば、16ビットCPUのデーターレジスターが16ビットの場合、計算する数値が32ビット以上の場合の数値の事をビッグNUMと呼ぶ。
ここでは、データーレジスターの2倍以上の大きさの二つの数値の加算、減算、比較について述べる。
(加算):二つの数値の小さい桁同士を加算して、キャリーフラグが出れば、次の大きな桁には、そのキャリーを含めて同じ桁数同士を加算し、次々と大きな桁同士を加算し続け、最大の桁数になったらそれを計算し終えて計算を止める。
(減算):二つの数値の小さい桁数同士を減算して、キャリーフラグが出れば、次の大きな桁には、そのキャリーを含めて同じ桁同士を減算して、次々と大きな桁同士を減算し続けて、最大の桁数になったらそれを計算し終えて計算を止める。
(比較):二つの数値の大きな同じ桁同士を比較して、等しくなく大小が決定した時点で比較を終える。もし等しくて二つの数値の各桁同士に大小関係が決定しない場合は次々と次の小さな桁同士を比較して大小が決定するまで比較し続ける。そして、最小の桁に行ってもこの比較が等しければ、二つの数値は等しいという結論に達する。
もし、途中で、大小関係が成立したら、そこで比較を停止する。
そして、その比較条件が、正式の大小関係となる。


4.分岐命令で使われる数値表現の統一。

数値表現は、Numericとアブソリュートの2種類が使える場合、できるだけアブソリュートを使う事。
特に分岐命令にNumericを使うと、マイナス条件とオーバーフロー表現において、分岐における比較条件が微妙に違って障害を起こす事が多いので、アブソリュートを使うべきである。(例えばアブソリュートでは64Kまでの数値表現ができる16ビット(64K)のデーターについて考えてみる。この16ビットの数値は、Numericだと32Kの数値を超えるとマイナスの数値になってしまう。32Kのあたりの数値ではアブソリュートでは正の数で連続であるが、Numericだと逆転して大小関係が逆転するのでメモリー空間を連続的に使うのにはNumericだと不向きなのである。数値表現において、アブソリュートとNumericを混同して考えて取り扱ってはいけない。)

※ 1Kとは、1024の場合と1000の場合がある。CQ誌のトランジスター技術の本では、大文字のKと小文字のkを使い分けて、1024と1000を表現する事となっている。ここで使われている34Kや64Kとは、1024の方を言い表している。


5.インターラプト・フラグのマスクの作法について。

インターラプトのマスクをSEI(セットインターラプト)、マスクのクリアーをCLI(クリアインタラプト)となっている。
インターラプトのマスクを必要とする処理には、次のパターンで記述してCLIを使わない事。
○ 処理の始め。
  フラグレジスターのPUSH
  SEI命令
○ 処理の終わり。
  フラグレジスターのPOP(PUL)
  リターン命令
こうすると、処理の終わりにCLIを使う必要も無くすっきりした表現となる。

インターラプトのマスクは、割り込み処理を実行する時に使われる。
割り込み処理の実行するために、SEIして始めてCLIをして終わらせるとすると、割り込み処理内で勝手にフラグレジスターが書き換えられてメイン処理をそのまま実行されてしまう恐れがあるので、フラグレジスターのPUSHとPOP(PUL)を使うのである。
また、割り込み処理と一般の処理が、同じメモリーやポートをアクセスするためのサブルーチンを作って使用する場合、通常処理に割り込みがかかってもフラグレジスターが割り込みの影響を受けないためにCLIを使わないインターラプトのマスクの技術を利用する事。
 この様なフラグレジスターを扱う処理とは、CPUのパイプライン処理により、実行される順番が遅れて実行される事があるのでCPUのメーカーによっては、フラグレジスターを運用する命令を使う前にNOPをいくつか入れる事を推奨される事が多い。
だから、事前に情報を得て安全確認をしておく事。
 もし、これをC言語などで使いたい場合、C言語にマクロ機能があれば良いのだが、もし、それができるとしたら、スタックの階層を同じくする工夫が必要である。そして、その場合、間違い率の低いプログラムパターンを使ってこのPISH POPを記述する事。


6.ジャンプ先のアドレスの書き換えの禁止。

 サブルーチンコール命令、ジャンプ命令のオペランドになっているアドレス部分のメモリーを書き換えてジャンプ先をコントロールするコーディングはやめる事。
ただし、インデックスレジスターを利用したサブルーチンコール命令、ジャンプ命令は、オペランドになっている部分を書き換える訳ではないので使用を許可する。
 理由は、CPUがパイプラインによって命令をフェッチしている場合、ジャンプ先を示しているメモリーアドレスを書き換えられてしまったらジャンプアドレスが不安定になってCPUが誤動作してしまう結果になる事が多い事と、こういうプログラムはジャンプ先は作った本人しか分からないプログラムであり他人にアセンブラのソースリストを見せてデバッグの依頼をしても何が何だが分らない可読性が弱いプログラムになる結果になる事が多いため。


7.状態遷移図がある場合の分岐の書き方。

タスクや割り込み処理の設計においては、特に状態遷移図が必要とされる事が多い。
この状態遷移図で記述する“状態遷移するプログラム”とは、まず初期状態があり、外部のイベントによって現在の状態の処理がどんな処理をして次にどんな状態になってどんな処理をしてゆくかという事を定めた連続性のあるプログラムの事である。
この連続性のある全体のプログラムは、各状態のプログラムの集合で構成され、各状態のプログラムはどんなイベントで何の処理をして次の処理へ主導権を渡すかを記述している。
この全体のプログラムが、各状態のプログラムへ実行の主導権を渡す手段となる仕組みの道具が、“状態遷移の状態を記述する変数”なのである。
この状態遷移があるプログラムの全体の構成とは、次の様な単純な構成となる。
○ 状態遷移図に従うプログラムを実行させる前に、“状態遷移の状態を記述する変数”の初期値を設定してイニシャライズする事。
○ 状態遷移のプログラムのエントリー(入口)部分を設定する。
○ “状態遷移の状態を記述する変数”に従って各状態のプログラムを実行する事。
○ 状態が変らなければならないイベントが発生した場合次の“状態遷移の状態を記述する変数”を設定し直す事。
○ 状態遷移のプログラムのエクジット(出口)部分を設定する。

この状態遷移図に従う全体のプログラムは、“状態遷移の状態を記述する変数”の値の大きさの順番に従いながら分岐するものであり、この分岐のあり方とはフロチャートで記述するプログラムの分岐部分を右から左へと順番に流れる様に記述する事。
その様に記述すると状態遷移図の変数の大きさの順番に従って流れる様に全体のプログラムを記述する事になる。
 この“状態遷移するプログラム”を設計するには、状態遷移図を書き、そのマトリックスを書いて状態とイベントと処理を定義して設計する事。
このマトリックスの記述とは、各状態のプログラムの処理内容とナンバーを表の横に記述し、イベントを表の縦に記述する。
マトリックスの内部のセルは、各状態のプログラムの処理内容がどのイベントによって何の処理をして次はどの状態のプログラムへ実行の主導権を移すかを“各状態のプログラムの処理内容のナンバー”で記述する事。
ただし、イベントがあっても各状態のプログラムは何も処理もせず他の状態のプログラムへ実行の主導権を移す事もしない場合は、空欄にしておくか、“-”でも記述して何もしていないという事を表現して定義し設計する事。

 この“状態遷移の状態を記述する変数”は、フラグ制御でなく数値制御にしておく事。
それはマトリックスに記述する変数が数値として表現されているという点で見やすいという理由の他に次の理由がある。
それは、その変数が8ビットデーターの場合、フラグ制御ならば8通りしか制御できないという制限があるが、数値制御ならば、2の8乗の256通りの制御ができる可能性がある。
また、その変数が、数値表現で表れている時は、インデックスレジスターを利用したジャンプ・サブルーチンをする処理に使う時も有効である。
その場合、ジャンプ・テーブルを定義して、“状態遷移の状態を記述する変数”の数値に従って、ジャンプ・テーブルのどこのアドアレスをインデックスレジスターに設定できる様にしておくという仕組み作りをしておく事が望ましい。

 さて、余談となるが、この状態遷移図だが、私の仕事で代表的な例を記述してみる。
(1) 割り込み処理の場合。
 通信プロトコルで受信電文のデーターを受信する部分である。
最初、STXコードを受信し、電文を受信し、ETXコードを受信したら、次、パリティーチェックをするという順番で受信電文のデーターを受信する。
このデーター受信の割り込み処理に状態遷移図が使われる。
(2) マルチタスクのタスクの場合。
 ベルトコンベアで物を流す場合、
その物が流れるベルトコンベアの部分にセンサーを配置して、そのセンサーで物の動きを把握して、どの様な作業をするかというスケジュールを書く時、タイムチャートも含めたシーケンスチャート図なるものをお客さんから資料として手渡される事があるものだ。
この図から、物が流れた場合、このタスク内の物の動きを表したシーケンスチャート図通りにセンサーがどの様に反応するかをチェックして、そのセンサーの反応からどの様な作業(モーターなどの装置を動作させたり停止させたり次のタスクを起動させたりする各種作業の事)をさせるかをシーケンスチャート図を見ながらプログラミングする。その時、設計する仕様にもれがあるかどうかを判断するために、そのタスク内の動きを示す状態遷移図とそのマトリックスを設計時に記述する。

代表的なのは、コピー機やプリンターの紙送りの部分においてセンサーを監視してモーターなどの各装置を動かすための各タスクの制御する部分の設計に状態遷移図とそのマトリックスを活用する。
また、通信装置においては、情報を送った後、レスポンスの待ち状態監視にタスクのタイマーによるWAIT状態を作り出す処理の部分などにも状態遷移図とそのマトリックスを活用する。
 このマルチタスクの場合の状態遷移図は、シングルタスクの環境内で、マルチタスクの動きをさせるプログラミングにも使われる事もある。
この場合、マルチタスクOS無しのシングルタスクでは、大きなループを作り、疑似WAIT状態を作るタスク・スイッチを使って状態遷移図によって作られた疑似タスクを順次動かしているプログラム構造になっているものである。


8.データーをテーブル化する事。

まずは、例として以下のプログラム作りのためにテーブルが用いられる。
(1) 特に数値などを表示するLEDによる表示板を使う時、そのフォントパターン、又は、ビットパターンを決定して利用するのにテーブルを用いる。(表示板に0~9までの表示、A~Zまでの表示パターンを作る時に利用する。)
(2) 数値変換のために利用する。例えば、EBCDIC(エビスディック)コードからASCII(アスキー)コード変換に利用したりする。また、データーの入出力のビットパターンが、ハードでの配線が仕様として間違って変更されている場合、それをハードの変更で処理するのではなくソフトの変更で対処する場合、元のデーターのビットパターンを変更して、間違ったビットパターンへ強制変更するために利用する。
(3) [logn(x)]の様な数値計算の計算値の獲得に数値変換テーブルを利用する事がある。これを使うと、計算時間を多くかけないで算出された答えを導く事ができる。特に、センサー入力の入力値の補正や、OUTPUTに使うデーターの補正のために、数値変換テーブルを用いてデーターの高速変換をしたりする。
(4) タイマーICからの割り込みを利用して、モーターの回転制御に使われる回転スピードの制御をする時、回転スピードをスムーズに上下させるためにデーターをテーブル化して利用する事がある。この場合のテーブル化とは、タイマーICに設定する値をテーブル化しておく事。このテーブルは、最初はゼロ回転であり、次は低速回転であり、だんだんと高速回転になってゆくための値を入れておく事。また、このテーブルには、モーターのスピードとして設定したい回転数の部分にはラベルを設けて、その回転数になったら定速回転になる様にプログラムを作る様にしておく事。
さて、データーテーブルを使わないでプログラム制御のみで実現するプログラムがあるが、その場合、デバッグする時や、仕様変更への対応を容易にする時、大変苦労する場合がある。
この苦労を少なくし、間違い率を少なくさせるために、データーテーブルを作って利用する事が奨励される場合がある。
それは、特定の部所のビットパターンの間違いは、プログラム変更する事無く、特定の部所のデーターテーブルを変更するだけで、間違いを簡単に修正できるというメリットがあるためである。
また、これは、プログラム開発の分業としても優位な場合がある。
それは、プログラム開発とデーター作成の作業を分業できるというメリットがあり、作業効率を高める事ができるためである。
テーブルを作成する時は、必ずそのテーブルの役目をドキュメントに書いて、参加するチーム全体にそのテーブルの使われる意味を知らして共有化させる事。
 ちなみに、プログラム作成のために、ジャンプ・テーブルを作る事もデーターのテーブル化の一環になるだろう。
その場合は、チーム全体にそのテーブルを共有化させる必要は無い。
しかし、ジャンプ・テーブルを利用するプログラムには、ジャンプ・テーブルと、ジャンプ・テーブルを使う変数の関係を仕様書に説明して記述する事。


9.ポートの入出力のON/OFFに関して。

 PIOなどを使ったポートの入出力の仕様に関して、ONとOFFの値が、1から0とか、0から1になるという仕様変更が多いものである。
それは、ハードウェア設計が正論理であったり負論理であったりする事と、ハードウェアのゲートICにインバーターのバッファーとしてのNOT回路が良く用いられるため簡単なハードウェアの仕様変更のために、その仕様変更をソフトウエアに求められるのである。
さて、その仕様変更に簡単に対応するためには、XORの演算子を用いる事。
XORの演算子は、1ワードのデーターの各ビットをビットごとに簡単に反転させるためにある。
XORするデーターのビットに1があるデーターのビットは、0と1とが反転し、ビットに0があるデーターのビットは、0と1との値が反転しない。
だから、もし、全ビットが1であるデーターとXORすると、そのデーターは、全データーが反転して、NOT演算子と同じ動きをする。
さて、XOR演算子を使えば、ポートから入出力されるデーターの各ビットの値をビットごとに値を簡単に反転させる事ができる。
だから、ポート入出力の部分には、必ずビット反転の変更に対応できる様にするための、そのポート固有のビット反転データーを設定し、必ずそのポートの入出力に使うデーターはそのポート固有のビット反転データーとXOR演算させて使う事。
そうすれば、入出力のポートの各ビットのON/OFFに関する仕様変更に対して、いつでも簡単に対応する事ができる。
 XORは、この様にして使うのだ。
その他の使い方とは、CPUの同じレジスターをXORする事によってCPUのレジスターを0(ゼロ)の値に設定する使い方と、CPUのレジスターが全ビットが1に設定された2の補数の整数値(整数値としては「マイナス1」という値になる)とXORする事によってNOTを実現するために使われる。
CPUのレジスターを0(ゼロ)に設定するのは、レジスターに0を代入すれば良いのだが、XORを使って0を設定する(ゼロクリアーする)方が、プログラムサイズが短くなるので使う事が多い。
※ 1の補数とは、その整数値のプラスマイナスの値を反転させるのに、全ビットを反転させた値。つまり各ビットのNOTと同じ。
※ 2の補数とは、その整数値のプラスマイナスの値を反転させるのに、全ビットを反転させた値にプラス1した値。この2の補数表現が、アセンブラで使われている代表的な整数値である。