復刻:キーワードガイダンス第13回「リード・モディファイ・ライト」2014年05月10日 01時04分18秒

初出:技術評論社「組込みプレスVol.15」(平成21(2009)年5月12日発売)

●内容の不定な上書き
ある会社では社員の行動予定の管理を共有エリアに置いた「予定表」というEXCELファイルにより行っていました。
社員全員の行動予定が記入できるようになっているファイルです。
このファイルの書き換えは基本的にはAさんだけが行う約束です。
社外からは電話をAさんにかけて予定表を書き換えてもらいます。

さて、Aさんはこの予定表の書き換えを以下のように行っていました。

(1) 共有エリアのファイルを自分のパソコンにコピーする。
(2) 自分のパソコンにコピーするのは出社直後の9時過ぎ
(3) 電話連絡は概ね10時前には終わるので、10時までは自分のパソコン上でファイルを修正します。
(4) 念のため10時過ぎまで待って、10時10分頃、自分のパソコンのファイルを共有エリアにコピーします。

●約束違反
そんなある日、営業のBさんが行方不明になりました。
予定表に何も書かれていないのに、出社してこないのです。
もちろん、Aさんにも予定を告げる連絡は入っていません。
この事件は営業担当Bさんの約束違反によるものでした。
パソコンやネットワークに詳しいBさんは会社の外から社内の共有エリアのファイルを読み書きできるようにしていました。

Bさんは客先に出かける予定をAさんに連絡するのを忘れていたため、当日の朝9時半頃に移動中のパソコンでネットワーク接続して、会社の予定表ファイルを書き換えたのです。

Bさんはこれで連絡できたつもりでいました。
ところがAさんはBさんに書き換えられる前のファイルを9時過ぎには自分のパソコンにコピーしていますから、Bさんの予定が入っていないファイルを編集して、10時過ぎには予定表ファイルを上書きしてしまいました。
当然Bさんの予定内容はなくなってしまいました。
このような経緯により、Bさんは行方不明となったのです。
Bさんの約束違反が全ての原因です。

●本当に約束違反か
実はBさんは、中途入社後半年も経っていたのですが、Aさんしか予定表ファイルを修正してはいけないという「約束事」を知らされていませんでした。
先輩社員はみんな「当たり前のこと」として周知すべき項目から抜けていたからです。
とりあえず、Aさんに連絡を入れるように、ということだけは聞かされていました。
そんなBさんは、いつもはAさんに予定の連絡はするものの、それは単なる「慣習」程度にしか考えていなかったのです。
実はBさんはこの半年の間、直接予定表ファイルを修正してしまっていました。
Bさんが予定表ファイルを修正するのは大抵、帰宅前。17時頃でしょうか。
そんな行き違いもあり、事件は発生したのです。

●リード・モディファイ・ライトとは
以上の事例がリード・モディファイ・ライトの全てです。
要するにリード・モディファイ・ライトは以下のように整理できます。

(1) データを別の領域にコピーする(リード)
(2) コピーしたデータの内容を修正する(モディファイ)
(3) 修正した内容のデータを元のデータに上書きする(ライト)

この操作を行うのが一つのタスク、一つの割り込み処理など、同一コンテキストだけであれば問題ありません。
問題が発生するのは複数のタスク、複数の割り込み処理で同一のデータの書き換えを行う必要がある場合です。

●リード・モディファイ・ライトの注意事項
以下の様なデータに対してはアクセス時の十分な注意が必要です。

・CPUの制御レジスタの書き換え
・ワンチップマイコン内蔵のI/O制御用レジスタなどの書き換え
・タスク関で情報伝達するために用意したグローバル変数の書き換え

リード・モディファイ・ライトが回避できないような処理にせざるを得ない場合には以下の対応策が必要です。

・リード・モディファイ・ライトを行う区間を割り込み禁止にする
・セマフォなどを使って、データの排他制御を行う
・アクセス関数を用意して、その関数経由でしかデータを操作できないようにする

リード・モディファイ・ライトが原因の組込みシステムの「原因不明の誤作動」は枚挙に暇がないくらいです。

復刻:キーワードガイダンス第14回「多重割り込み」2014年05月11日 02時40分14秒

初出:技術評論社「組込みプレスVol.16」(平成21(2009)年8月28日発売)

●順番待ちの仕組みと処理の順番
変わったハンバーガーショップを考えて見ます。
レジ待ちの列はA列、B列、C列の3列としましょう。
レジ係は1人しかいません。
同時に複数の列にお客が並んだ場合はA列>B列>C列の順に接客します。
レジ係は注文を聞いて会計を済ませて調理係に依頼すると次の客の注文を取ります。
会計済みで注文品受け取り待ちの客には列の脇に避けてもらいます。
注文品は調理係が準備を済ませると受け取り待ちの客に渡します。

●多重割り込みの二つの例
ある時A列とC列に同時に客が並びました。
レジ係はA列に客が並んでいるのでC列の客は待たせたままA列の客の注文をとります。

(a) 注文品の単価と個数のレジ入力
(b) 客からお金を受け取る
(c) 調理係に注文を伝える
(d) 客にお釣りを渡す

上記が済んだら次はC列のレジの処理のはずですが、
気付いたらB列に客が並んでいます。
レジ係はC列の客は待たせたままでB列の注文を取ります。
このように「多重割り込み」には大きく分けて二つの場合があります。

(1) 同時に二つ以上の要因の割り込みが発生した場合
(2) 一つの要因の割り込み処理中に別の要因の割り込みが発生した場合

この例は多重割り込みの二つの例の複合例です。

●割り込み優先度と割り込み禁止区間
割り込み優先度は同時に割り込みが発生した時の処理の順番の約束事に過ぎません。
仮に、優先度が低いC列の会計処理中に優先度の高いA列に客が並んでも割り込み禁止のままの場合は無視するしかありません。
何が何でもC列の処理を中断してA列の処理を「優先する」という意味の優先度ではないのです。

但し、以下のような工夫は可能です。

レジ係の手順を以下のように変更します。
(a) 注文品の単価と個数のレジ入力
(b) 優先度の高い列に目を向けて客がいればそちらの注文取りを先に行う
(c) 客からお金を受け取る
(d) (b)と同じ
(e) 調理係に注文を伝える
(f) (b)と同じ
(g) 客にお釣りを渡す

最初の手順では(a)~(d)の区間を「割り込み禁止区間」としています。
一方、あとの手順では(a)の区間だけを「割り込み禁止区間」とします。
注文を忘れないためのレジ入力が済んだ時点までを割り込み禁止という扱いにしたからです。
一部のワンチップマイコンの割り込みコントローラは割り込みが発生すると最初に割り込み禁止にした上で、その時点で一番優先度の高い割り込み処理に
CPUを割り当てます。
割り込み処理の任意の部分で意図的に割り込み許可にしない限り、優先度の高い割り込みが優先度の低い割り込み処理中に発生しても優先度の高い割り込み処理は実行されません。

●割り込み保留可能時間と割り込み禁止時間
通常、割り込み要因の発生には周期性があります。
その周期未満の時間は割り込みが発生したことを保留にして他の処理を行うことが出来るのです。これを「割り込み保留可能時間」といいます。
「割り込み禁止時間」は「割り込み保留可能時間」を越えないように実装する必要があります。
これは多重割り込みが発生する可能性も含めて全ての組み合わせで条件を満たす必要があります。
なお、割り込み要求はレジスタに保持されますが、その情報をクリアしないと次の割り込みは発生しません。

●同じ要因の多重割り込み
実際にはそれぞれの列に複数の客が並ぶことは出来ません。
もし、割り込み処理中の割り込みと同じ要因の割り込みが発生する場合はシステムの要求スペックをハードウェア仕様が満たしていないことになります。
したがって、ハードウェア設計上そのような処理を行う場合の仕組みについて検討する必要は全くありません。
逆にソフトウェアでは工夫を行って、割り込み禁止時間を短縮するようにします。
ハードウェアで工夫を行う例としては、受信バッファ1段のチップからFIFOバッファを持つようなチップに変更するようなことが考えられます。
FIFOバッファ分の受信データが溜まるまでは割り込みを保留に出来るため、割り込み保留可能時間が延びて、CPUには余裕を持たせられるからです。

復刻:キーワードガイダンス第15回「インスタンス」2014年05月13日 21時01分20秒

初出:技術評論社「組込みプレスVol.17」(平成21(2009)年11月13日発売)

●モノの実体としてのインスタンス

お弁当屋さんでお弁当を買うことを考えて見ましょう。

メニューには幕の内弁当、から揚げ弁当、コロッケ弁当があるとします。
Aさんは幕の内弁当、Bさんはから揚げ弁当、Cさんはコロッケ弁当を購入しました。
それぞれ持ち帰ることが出来るお弁当の実体は別々に存在します。

一方、幕の内弁当にはから揚げとコロッケが含まれます。
から揚げ弁当にはから揚げ、コロッケ弁当はコロッケがそれぞれお弁当のおかずの主役です。
幕の内弁当に入っているコロッケとコロッケ弁当に入っているコロッケは同じ種類のコロッケで別々に実体が存在します。

「お弁当」という枠組みでの実体とお弁当の中身の「おかず」としての実体はどちらもインスタンスの具体例となります。
また、インスタンスの捕らえ方の範囲について、お弁当という中身の詳細を問わない概念、おかずの組み合わせに着目した概念、お弁当のおかず単体に
着目するような概念など段階があることも分かります。
この概念的な段階を「抽象度」とここでは定義しておきます。

●オブジェクト指向から独立したインスタンス

以上のようなたとえ話はインスタンスという言葉とともにオブジェクト指向の説明として語られることが多いようです。

また、言語処理系、例えばC++やJavaなどに依存して語られることも一般的です。
ですが、インスタンスという言葉をオブジェクト指向とは無関係に使うこともできます。
例えば、リアルタイムOS上のタスクとオブジェクト指向のオブジェクトは概念も実装方式も異なりますが、タスクの実体を指すときにインスタンスという言葉を使った方が大雑把な概念的な理解のきっかけとなります。

「タスクはメソッドだけを実体化したインスタンス」

というようなオブジェクト指向風に大胆に簡略化した説明を行った方が、大筋では会話が成立してしまいます。
本当はリアルタイムOSの仕組み上のTCB(タスク・コントロール・ブロック)の説明とレジスタ退避、スケジューラによるコンテキストスイッチなどの正確な説明を行う必要があるのですが、全体的な設計上の概要把握だけが目的の場合はOSの仕組みまでは理解していなくても話を進められます。

つまり、オブジェクト指向用語が他の実装や設計に対しての「たとえ話」に使えるようになってきたということです。
また、このようなアプローチをすると、リアルタイムOSのタスク生成における「同一機能タスクの複数生成」という概念も説明しやすくなります。
なお、お弁当の例は振る舞いのないデータだけのインスタンスのたとえ話でしたが、タスクの例は振る舞いだけのインスタンスのたとえ話になります。
リアルタイムOSでは振る舞いのインスタンスとデータのインスタンスは別々に管理されています。

●組込みシステム特有の問題

これまでのたとえ話のインスタンスをソフトウェア実装の視点で見れば全てメモリ領域に独立して存在するデータの集合と言うことが出来ます。
おかずを表す変数データとおかずやご飯を格納する「容器」は全てメモリ上のデータやデータの並びになります。
オブジェクト指向言語仕様上はこのメモリ確保と管理の仕組みをどのように表現するかということに重きが置かれています。
ですが、どのメモリにインスタンスを配置するかということはあまり議論されません。
インスタンスを高速なSRAMに配置するのか、普通のDRAMに配置するのか、もしくは静的にインスタンスを生成した上でROMに配置するのか、などの議論です。

これらの議論は組込みシステムでは必要な場合があります。
組込みシステムではお弁当の容器を選択したい場合があるからです。
プラスチック容器、紙の容器、竹の容器、持ち込みの自分用の容器など出来合いのお弁当屋さんの既定容器以外の容器が使える必要があります。
つまり、メモリ配置について意図的に指定する必要があるということです。
単なるクラス全体のメモリ配置の問題だけなのであれば、メモリ配置のためのコンパイラの拡張書式を使えば解決します。
通常、組込みシステム用のコンパイラにはこのような目的の拡張書式があります。

但し、クラスや機能全体ではなく一部の特定部分だけが性能上の問題になる場合には、抽象度を上げた実装をわざわざ解体し、抽象度を低くした上でメモリ配置を変える必要があるかもしれません。

復刻:キーワードガイダンス第16回「コールバック」2014年05月18日 22時52分26秒

初出:技術評論社「組込みプレスVol.18」(平成22(2010)年2月26日発売)

●通知と代行
自分のやることを忘れないために以下のような方法があります。

(1) 実行を忘れないように実行時期を誰かに教えてもらう
(2) 実行そのものを誰かに代行してもらう

ここで、クリーニングの受け取りについて考えて見ます。

Aさんはクリーニング屋さんにクリーニング完了のタイミングでメールや電話で連絡してもらえるサービスを利用しています。
クリーニング屋さんからの連絡後、自分の空き時間でクリーニング屋さんに取りに行くことになります。

Bさんはクリーニング屋さんと提携している代行業者にクリーニングの受け取りを依頼しています。
業者にはクリーニングされた衣類をクリーニング屋さんからの受け取り後に自宅の宅配ボックスや勤務先に届けてもらいます。
届け先や完了時の連絡方法などはオプションでその都度変更が可能です。

Aさんの場合は連絡してもらうだけで、実行は常に自分の責任で行います。
面倒ですが自分で状態やスケジュールを調整して受け取りを実行するので、行き違いは発生しません。
Bさんの場合、自分の都合で自ら実行するような場合や複数の業者を使い分けるような場合には自分と業者や業者同士の調整をするのに却って手間がかかってしまいます。

●イベント通知の手法と開発効率
コールバック(callback)はコールバック関数(callback function)の省略形として使われる場合やコールバックルーチン(callback routine)の省略形で使われる場合があります。
本来は電話をかけた相手から依頼した結果を折り返し連絡をもらうような場合に使われる用語です。

開発実装上は以下のような使われ方をします。

(a) 依頼先のイベント通知処理に対して関数ポインタを引数として渡すことにより自分で作った関数を依頼先に登録できる
(b) イベント通知の種類毎に自分で作った関数を使い分けることができる
(c) イベントの種類を一つのコールバック関数の引数でもらえる仕組みもある
(d) 非同期処理の場合にのみ使われる

多くの場合、コールバックの仕組みはOSが提供する場合やミドルウェアの特定のSDK(Software Development Kit)としてのAPI(Application Program Interface)が提供する場合があります。

自分が作りたいプログラム(アプリケーション)と汎用的なSDKが提供する機能を分離することが主な目的となります。
このような機能の分離はソフトウェアの可搬性や開発効率を高めます。

●組込みとPC用OSとの違い
WindowsなどのPC用のOS上で動作するアプリケーションを開発する場合、明確な開発に関する作法がSDKやOSにより決まっています。

自分が作っているアプリケーションは特に意識しない限り、言語処理系とSDKの連携で比較的簡単に矛盾のないアプリケーション開発が可能になっています。

中身の仕組みは別としても自分(アプリケーション)の責任範囲が明確な開発が出来るようになっています。
実行コンテキストについての配慮や資源同期の配慮も不要です。
アプリケーション開発者視点で考えるとAさんのパターンと同様です。

ところが組込みシステムで採用するようなコールバックの仕組みはまちまちです。
「コールバック」という用語が一人歩きするだけで実装の仕組みは決まっていません。
開発する会社やチームの違いによっても実装の違いがあり得ます。

これはBさんと業者の関係に似ています。

以下の留意が必要です。

・非同期イベント検出の起点は割り込み処理
・繰り返し状態を見るようなポーリング処理でイベントを検出する場合もある
・イベント検出後のコールバック関数の実行は割り込み処理の場合や自分以外の他のタスクである場合が多い
・SDKとして提供されてソースコードが見えない場合はコールバック関数の実行コンテキストについて把握しておく必要がある
・アプリケーションとコールバックの実行コンテキストが異なる場合は資源の排他制御が必要

このように、アプリケーション開発者が一定の基準でコールバックを捉えていたとしても実行コンテキストや資源同期の仕方が同じであるということが保証できない場合があります。

これはOSを使わない組込みシステム、μITRONを使った組込みシステムでの開発特有の問題です。

復刻:キーワードガイダンス第17回「仕向けと地域化」2014年05月24日 06時00分59秒

初出:技術評論社「組込みプレスVol.19」(平成22(2010)年5月6日発売)

●海外製品とOEM製品
日本で発売される製品と同じ外観、同じデザインのものが海外で販売されているのを目にすることも多いと思います。
ですが日本で売られているものと細かいところで異なる点もあります。

(a) 型番や製品名
(b) 機能の増減
(c) 表示される言語の違い
(d) 電圧などの違い
(e) 物理的な配置の違い

自社のブランドをつけた市販品と他のメーカに製品を供給して供給先のブランドとして販売されるようなOEM製品という扱いもあります。
これは日本のメーカでは「仕向け」という言葉で表現されます。

本来は単なる「送り先」というような意味ですが、基準となる製品の派生製品を指す場合に使われる言葉です。

●部品の共通化
メーカでは派生製品を製造する場合には出来るだけ部品を共通化することが行われます。
同じ部品を数多く使う方が製造原価が下がるためです。

但し、ここでいう「共通部品」というのはハードウェアについてのことであり、多くの場合ソフトウェアは含まれていません。
このため、ソフトウェアの共通化を視野に入れて設計を行う要求仕様そのものが発生しません。

共通化を最初に視野に入れるかどうかで派生製品の開発のやり方が全く異なってしまうのですが、共通化するための設計および実装工数は配慮されないままに開発が行われることになります。

製造原価という視点では開発工数が増加するかどうかはあまり問題視されないからです。

●国際化と地域化
PCで動作させるソフトウェアでは国際化(internationalization)と地域化(localization)という思想でソフトウェアが組み上げられることが一般的になっています。
主に日本語や中国語のようなマルチバイト言語の切り替えに対する配慮が共通部品として提供されているような仕組みです。

共通部品化されたソフトウェアをベースにアプリケーションを開発すれば、言語切り替えの仕組みに対する切り替え処理と定義データの差し替えを行うだけで、ソフトウェアの処理ロジック部分には手を加えることはなく、製品を開発することができます。

このような考え方は開発工数の削減には非常に有効なものです。
このように、地域化は国際化を前提とした対になる表現ですが、「仕向け」はソフトウェア上の「共通部品化」を前提には考えられていません。

そして、組込みソフトウェア開発以外では「仕向け」という言葉が使われることはほとんどなく、汎用的なOSを使わないような組込みソフトウェア開発では
「ローカライズする」というような言葉が使われることもほとんどありません。

●仕向け対応の実際
このような状況で、汎用的なOSを使わない組込みソフトウェアの開発では以下のような開発が現実には行われることになります。

(1) 基準製品の開発時の開発予算には共通部品化の予算は含まれていない
(2) 仕向け対応はその製品単位の要求仕様を満たすものだけが行われる
(3) 仕向けの切り替えは動作中には行われないものとして設計される
(4) ソースプログラムに複数の仕向け用の記述を網羅してコンパイルの
  段階で切り替えられるようにする

(4)の対応で充分にソフトウェア開発上の問題は解決しているように見える場合はもちろんありますが、実際には仕向けの組み合わせによってタイミングが異なることもあり、正常動作していたはずのソースプログラムにまで手直しが必要な場合もあります。

例えば、A機能、B機能、C機能の処理ブロックがある場合、A機能だけの仕向け製品、B機能だけの仕向け製品、C機能だけの仕向け製品というような場合には正常に動作していても、A機能とC機能を組み合わせた仕向け製品では正常に動作しないということがあるわけです。

また、A機能、B機能、C機能を全て有効にするような仕向けが発生した場合、プログラムを格納するROM領域が足りなくなったり、使用するRAM領域が足りなくなるようなことが考えられます。

単純にハードウェア部品としてROMやRAMのサイズを増やせるような場合はソフトウェアに対する影響は少ないものになりますが、製造原価に直接響くような対応は後回しにされます。

このような場合はROMやRAMのサイズを増やさないでも納まるようにソフトウェア全体を見直して作り変えることが第一に検討されます。