セマフォ+共有メモリを捨て高水準ITCへ:Symbian OS開発の勘所(9)(1/3 ページ)
プリミティブなAPIに固執する態度を改め、必要に応じて高水準のITCを使うことが「車輪の再発明」を廃絶する近道だ
前回はSymbian OSにおける基本的な機能分割の枠組み、クライアントサーバ・フレームワークを解説しました。「いや、どうでもいいよ。セマフォと共有メモリがあれば、後はうまくやるから」というアプローチについては、前回の解説でいくらか誤解を解くことができたのではないかと思います。
もちろんクライアントサーバ・フレームワークだけですべてのITCデザインを網羅できるわけではありませんが、ではクライアントサーバで都合の悪い部分はセマフォ+共有メモリの出番なのかといえば、そんなこともないようです。それ以外のITCスタイルをOSがサポートする必要性はSymbianでも理解されており、その結果としてV8.1b以降いくつかの新ITC機構が導入されているからです。
今回はクライアントサーバ以外のITC形態についても、OS提供の高水準な機能を使う方がリーズナブルであることを、マルチタスク・ITC関連の諸要素を概観しつつ解説していきます。
マルチタスクにかかわる諸要素
まずは足元の点検です。これからの検討を簡単にするために、第8回までに登場した、マルチタスクにかかわる諸要素を地図にまとめます。X軸としてデータに着目した機能なのか、コードに着目した機能なのかの別を、Y軸には機能のレベル(プリミティブなものなのか、フレームワーク的な複雑なものなのか)を取り、諸要素の関係を整理してみたのが図1です。
プロセスやスレッドは第2回で解説したとおりですが、セマフォやミューテックス、共有メモリはまだでしたね。良い機会なのでここで解説しておきましょう。
マルチタスクにかかわる諸要素 − セマフォ
Symbian OSのセマフォは、標準的な計数セマフォです。同時に動いて構わないエンティティ(要するにスレッド)の数を、セマフォの初期値として設定します。
資源を獲得するためのP操作に対応するAPIはWait()で、発行するとカウンタをアトミックにデクリメントします。発行したスレッドの実行は、カウンタが非負であれば継続、負になった場合はブロックされます。
資源を解放するためのV操作に対応するAPIはSignal()で、発行するとカウンタをアトミックにインクリメントします。発行の結果、カウンタが負から0に切り替わるのであれば、カーネルは次の待ちスレッドを解除します(が、そのスレッドが動作するか否かは当然優先順位などに左右されます)。
セマフォの実体はカーネルに確保されるので、ユーザー側からRSemaphoreクラスを通じて操作を行うことになります。
マルチタスクにかかわる諸要素 − ミューテックス
クリティカルセクションを排他的に実行したい場合のために、ミューテックスが用意されています。セマフォの場合と同じく、実体はカーネルに確保され、ユーザー側ではRMutexを用いて操作を行います。
Symbian OSはv8.1bから4段階の優先順位に基づくスレッドのスケジューリングを行うリアルタイムカーネルとなりましたが、その際ミューテックスには優先順位継承の機能が導入されています。ところで優先度がないOSから来られた方はご存じないかもしれませんが、優先順位に基づくリアルタイムシステムには「優先順位の逆転」という問題が存在します。
これを称して「優先順位の逆転」といいます。これによるシステム障害の例として広く(かな?)知られているのが火星探査機マーズ・パスファインダーで発生した問題です。例えば以下に示すURIに適切にまとまっていたので、興味がある方はご覧ください。
この「優先順位の逆転」を回避する方法の1つが優先順位継承です。考え方は以下のとおりです。
あるタスクXのクリティカルセクションが、より優先順位の高いタスク(群)をブロックしている場合、Xの優先順位をブロックしているタスク(群)と同格にして実行する
クリティカルセクションの期間、割り込みを禁止することで(上述の例でいえばYの実行)「優先順位の逆転」を防ぐ方法もありますが、応答性を考慮するとリアルタイムシステムでは優先順位継承の支援を受けるのが一般的です。そのようなわけで、リアルタイムカーネルへの移行と同時に優先順位継承の機能が支援されています。
マルチタスクにかかわる諸要素 − 共有メモリ
共有メモリとはプロセスバリアを超えて、複数のプロセスからアクセスできるメモリです。ただしこの概念はOSごとに提供方法がずいぶん異なっています。素直に共有メモリと呼ぶもの、メモリマップドファイルとしてファイルのセマンティクスで扱うものなどさまざまで、ファイルやソケット(注1)、セマフォなどがOSごとにそれほど違わないのと比べると、モデルのばらつきがかなりあります。
Symbian OSではそのためにRChunkというクラスを用います。グローバルチャンクと呼ばれる共有メモリを確保するには、このRChunkのインスタンスに対して下記のAPI、
TInt CreateGlobal( const TDesC& aName ,TInt aSize ,TInt aMaxSize ,TOwnerType aType=EOwnerProcess);
を発行します。単なるCreate()という名前でないのは、RChunkはプロセスローカルなメモリ、ローカルチャンクを確保することもできるからです(こちらの方のAPIはCreateLocal())。RChunkはメモリの固まり(chunk)を扱うのが仕事であって、それがローカルかグローバルかは差異にすぎないとするAPIシンタックスです。やはりSymbian OSでも提供の仕方はほかのOSと異なっていましたね。
Copyright © ITmedia, Inc. All Rights Reserved.