表現系工学特論第4回 (1)モデル検査(1) 並行システムとモデル検査

表現系工学特論第4回
(1)モデル検査(1) 並行システムとモデル検査
それでは今日からはテーマを少し変えまして、モデル検査というテーマを、今日を含め
て4回講義をする予定です。今日の第1回目は基本的な概念を説明する程度の内容になっ
ています。
それでこれはどういうものなのかと言いますと、前回までは逐次的なプログラムという
学部に入ってすぐ習うような、C言語で書くような1本のプログラムを実行した時にそれ
を検証する、正しいかどうかを証明するという方法を勉強しましたけれども、今日からは
この逐次プログラムではなくて並列プログラム、プログラムが並列に何本も動く、そうい
うようなものです。それで全体で1つのシステムとなっているものを並行システム、並列
システムと言ってもいいかもしれないのですけども、並行システムということにします。
そういうものがソフトウェアとして正しいかどうかというのはどうやって調べるか、そう
いうような問題意識のものです。それで並行プログラムと言っても1本1本は逐次プログ
ラムなので、前回まで勉強した逐次プログラムが正しいかどうかというチェックの仕方と
いうのは、相変わらず重要で役に立つのですけども、並行システムの場合はそれに加えて
さらに難しい側面が出てきます。プログラム同士がお互いにインタラクションしますので、
いろいろ難しい面が出てきます。それをどうやってやるかということです。そのテクニッ
クとして今注目されている、有望だと思われているのがモデル検査、英語で Model
Checking と言いますけれども、そういうものが実用化されつつあるというか実用化の手前
くらいまで来ている感じで、産業界でも非常に注目して、学会というアカデミックなこと
をやっている大学の先生とか研究者とかもこういうことは元々やっていますけれども、産
業界まで巻き込もうとして今進んでいる段階なのです。そういうようなものを皆さん方に
紹介したいと思います。
参考文献としてはあまりまだないのです。これは非常に新しい技術なので、あまりない
ので英語になるのですけども、Model Checking というクラークという人達が書いた 1999
年の本、これが改訂されて行って 2000 何年かに改訂版も出たのかもしれないですけども、
これが最初の教科書なのです。日本語英語何語という言語に係らず1番最初に出た教科書
が 1999 年なので、それ以前は教科書を使って教えるという内容ではなくて、先端的な研究
者が一生懸命研究していて、論文がいろいろありますという世界だったのです。この辺り
からもう実用的に使えるのではないかということで、一般の技術者や大学生、大学院生に
も教えるべきだということになって、こういう教科書が作られた。その後いくつかまた教
科書が増えてきたり、日本語でこれだけの教科書というのはないのですけども、産総研、
国の産業技術総合研究所でこういうことをやっているセンターがあるのです。システム検
証研究センターです。関西にあります。そこの人がやはりこの一般技術者向けにこういう
講座を開いたりして、その教科書らしきものを作っているとか、そういうような現状なの
です。ですから、大学院とか学部でこういう授業をやっているという大学も、そんなに多
分多くはないと思います。まあ日本を代表するような拠点の大学は、きっとこういう授業
がどこか1つはあると思うのですけども、そうではない 50 も 60 もある大学の全部で、こ
ういう教育をやっている訳ではない。そういう技術なのです。
今日の話はまず並行システムとはどういうものでしたかというのを簡単に紹介します。
情報系の学部出た人はもう知っていることと思うのですけども、それ以外の流れでこの大
学に入った人はもしかしたら知らないかもしれないので、簡単に紹介します。
そしてモデル検査というのは一体何をやるものなのか。中身はあまり説明しないのです
けども、要するに何をやるものかというと、ユーザーとして見た場合、どういうものを入
れたらどういう出力が出てくるのかというくらいの話をします。
それから3つ目は、このモデル検査というのはそういうソフトウェアのシステムで、ユ
ーザーとして見ればダウンロードしてすぐ実行して見られるようなものです。ですからど
ういうようなシステムが今使えるのかという。それからその中身はアルゴリズムというの
は非常に難しくて、今日から4回くらいでは到底説明できないので、この授業ではもう説
明は諦めているのですけども、概略、すごく超基本的な考え方として、どんなことを考え
て内部でアルゴリズムが実行されているという、ちょっとだけを話します。それでこうい
うことに興味を持って、本当に内部で何をやっているかというアルゴリズムの詳しい内容
を知りたい人は、おそらくコンピュータサイエンス専攻の方で非常勤講師を呼んで特別講
義とか、そういうことを検討されていると思います。昨年も確かそうだったと思います。
そこは国立情報学研究所、NII の人を確か呼んでいると思うのですけども、そこもやはり最
近興味を持っているのはこのモデル検査の辺りを中心に、教材等を作っているということ
だったので、そっちの方ではこれだけの話をもっと深くやると思います。私共の講義では
あまり深くやらずに、ユーザーとしてこれくらいのことを知っていればいいのではないか
という、これからの次世代のソフトウェアの研究者、技術者にとって常識となるのではな
かろうかと思われることを、ちょっと早めに皆さんにお伝えしておく、それくらいの内容
になっています。
(2)1.並行システム
まず最初の部分、並行システムの紹介なのですけれども、内容的にはそもそも並行シス
テムとはどういうものか、それからプログラムをここではプロセスと呼ぶ訳なのですけれ
ども、プロセスが複数個走っていますので、それが全く無関係に独立にプログラムが動い
ているだけなら何も難しいことはないのです。お互いにインタラクションする、通信によ
ってインタラクションをすることによって難しさが増えてくるので、その話をちょっとし
ます。それからインタリーブというのは、複数のプログラムを複数のプロセッサ、CPU で
実行するというのもあるのですけれども、1台の CPU で複数のプログラムを動かすという
こともあります。その時の話です。それから相互排他というのは、1つのリソース、例え
ばプリンタとかを2つのプログラムで同時に使ったりはできないです。2つの出力がまぜ
こぜになってプリンタに印刷されたら困ります。ですから共通のリソースというか資源を
自分だけが使うという、お互い他の人を排除して使うということが必要になるのです。そ
ういうような話をします。それからデッドロックというのは2つのプログラムが動いてい
るのですけれども、何かの関係で暗礁に乗り上げて、お互いに相手が何かするのをじっと
待っている状態になって、お互いに見つめ合ってそれ以上動かないということがあるので
す。そういう現象について話をします。それからライブロックというのは、今度は全体と
してはちゃんと動いているのだけれども、誰か1人が犠牲になっていつまで経っても自分
の番に回ってこない。例えばそのリソースというのが食べ物だとすると、餓死して死んで
しまう。それに相当するような現象が起きたりします。そういうような話を紹介します。
(3)並行システム(1/7)
まず1つ目の並行システムというものはそもそも何かということです。これは英語で
concurrent systems という風に言います。並行というのは concurrent というのを日本語に
訳したものです。私がさっき口で並列と言っても良いかなと言いましたけれども、並列と
いうのは英語で parallel と言います。平行四辺形とかという2直線が平行だというのの平
行となります。parallel です。それに対して concurrent というのはほとんど同じ意味で使
っていますけれども、理論系の研究とか教育ではこの並行という言葉を使うことが多いで
す。物理的に本当に並列で動いているという時は parallel です。concurrent は物理的に並
列でないかもしれないけれども、論理的には並列と考えられるという意味では、ちょっと
広い感じがしますので、concurrent という言葉を使います。この current という言葉は、
ここの情報科学研究科というのは実際には情報エレクトロニクス系ということで電気系の
人も含んでいる訳です。エレクトロニクスも含んでいる。で、電気の方で current というの
は電流という意味です。electric current という。electric というのは電気です。current と
いうのは流れという意味です。con というのは元々多分ラテン語とか何とか、英語とかフラ
ンス語とかそういう言葉をずっと遡っていくと、ラテン語とかそういうところからいろい
ろ来ているのです。そこの接頭語というか、いろいろな言葉の前に con というのが付いて
さらにいろいろな意味を付け足しているのです。どうやら複数のものが何かお互いにイン
タラクションするとか協力するとか、そういうような概念を表しているようなのです。で
すので、current というのは流れが複数個あるということです。流れというのは当然フロー
チャートというコンピュータのソフトフローチャート、流れ図で書いたりします。あの流
れのことです。1本のプログラムは1つの流れがある。例えば IF 文というか菱形で条件を
判定して yes か no かで枝分かれする場合があったにしても、必ず yes か no かで毎回毎回
どちらか1本だけを取ります。ですから流れとしては1つのプログラムは1つの流れしか
ない。複数のプログラムを動かすと複数の流れが出てくるのだけれども、それが独立でや
らなくてお互いに協力し合ったりする、そういうようなイメージの単語になっています。
そういうものです。
それで言葉で説明したものがこれなのですけども、複数のプロセスが並列に動作する計
算システム。プロセスとは何なのかとかこういう話をしだすともうどんどん狭い話になっ
て行って、OS がどうなっているかとかそういうすごく細かい話になってきますので、いつ
まで経っても終わらないのです。プロセスというのは逐次的なプログラムを1つ実行して
いるものと思ってください。ですからプログラムというのと大体同じなのだけれども、同
じ1本のプログラムを同時に3つ4つ動かしているかもしれないです。あまりそんなこと
はないかもしれないですが、例えばワープのプログラムと同じプログラムを4つ動かして
いるとか、ブラウザを4つ立ち上げているとかというかもしれない。その場合はプログラ
ムは1つだけどプロセスは4つです。そういう風に、実際に動いている単位をプロセスと
言います。そういうものが複数個ある、2つ以上ある。それからそれが並列に動作すると
いう、直感的なイメージで良いと思います。本当に同時に動いている。1つ終わってから
次のプログラムを動かすというのではなくて、同時に動いているということです。
それから後この擬似並列というのは、本当は同時に動いていないのだけれど、見掛け上
同時に動いているように見えるというソフトウェアのテクニックなのです。後で簡単に紹
介しますけれども、本当は物理的には並列ではないけれども、論理的に見掛け上並列に見
えるという、それも含めて並列に動作する計算システムだという風に定義をします。これ
は別に数学的な定義ではないので、これくらいの定義で良しとすることにします。
例えばの例なのですけども、リアクティブ・システム、応用分野というのがあります。
このリアクティブという言葉の意味は、直ちに反射的に反応するというような意味です。
特に現実の制御系とかロボットのシステムとかそういうようなものがこれに該当するので
すけども、情報システムというのはどこかの何らかの環境に置かれます。もしエージェン
トという言葉を知っている人がいれば、そういうものが出てくるのですけども、そうでな
くても情報システムというのは何らかの環境に置かれます。その教室の中に置くとかイン
ターネットで世界に繋がっている環境に置くとか、ロボットだったら周りにいろいろ人が
あって、廊下があってとかそういう環境に置くとか、何らかの環境に情報システムを置く
訳ですけども、そこからイベントというのが入ってきます。例えば通信回線からメッセー
ジが来るというのもイベントですし、誰かがマウスをクリックしたというのもイベントで
す。それからロボットだったら目の中に突然何か怪しい光が入って来たというのもイベン
トです。そういうものに反応してシステムが動くということがあります。その場合大抵は
実時間、リアルタイムで動く。ロボットが何か見てからすごいじっくり考えて、10 年後に
行動を起こしたとかいうのでは駄目です。何か見て即座に1秒以内に行動しないといけな
いというリアルタイム性があります。ですからこういう環境からのイベントの入力に対し
て、リアルタイムに応答して行動するような並行システムがあるとすると、そういうのを
リアクティブ・システムと言ったりします。こういうものにも関係しています。これは並
行システムでない場合もリアクティブ・システムと言います。この種のものは大体リアク
ティブになっているということです。例えばロボットだったら目から入ってくる画像を処
理するような処理をしている部分と、頭脳の中で人工知能のアルゴリズムが動いてさあど
うしようかと考えているようなのとか、足を動かすモーターを制御しているプログラムと
か、1つの CPU で全部やっているというのはあまりないのかと思います。大体これくらい
の複雑なものだとそういういろんなプロセッサが同時に動いていることがあります。例え
ばそういうものが考えられます。
最近だったらパソコンでもそんな風になっています。昔のパソコンは CPU が1個だけ
あるので、こういう並行動作はしなかった訳ですけれども、今だったら1つの CPU でデュ
アルコアという、CPU としては1個だけど中身をよくよく見るとプロセッサが2個入って
いる。そういうのをコアと言っています。そういうようなものだったら、デュアルコアと
いうのはコアが2つあるということなので、そういうパソコンの場合、プロセッサが2個
あるので2つまでは物理的に、本当に並列に動作するようになっています。2つといって
も少ないのですけども、2つの処理を同時にやりますので、少なくとも1番ラッキーなケ
ースで速さが2倍になる訳です。それからクワッドコアと言ってもう少し高いパソコンだ
と、クワッドと言うと4という意味です。4つのコアが入っている。この場合は4つのプ
ロセスが同時に走ります。もっと値段が高いのだったら、クワッドコアという CPU を4つ
入れていますという、それはもうパソコンと言って良いのかどうか、サーバーと言って良
いかもしれないですけど、それだったら 16 同時に走るとか。では同時に走らせたいものを
50 あったらどうするのか、16 のコアで 50 走らせるにはどうするかというと、擬似並列と
まぜこぜにする。16 個だけは物理的に本当に同時に走るのだけども、残りの 50-16 の残
りのものも、あたかも同時に 50 個走っているように擬似並列するという風になります。そ
ういうような時代になって来ているのです。
(4)並行システム(2/7)
それでそういうシステムを実際にどういう風に実行するかという、いろんな観点から分
類することができますけれども、実行方法の観点から2つに分類するとこういう分類がで
きます。
1つは非同期・交互実行。非同期というのは asynchronous、同期実行というのは
synchronous とこの次に出てきますけれども、a が付くのは a というのはこの場合否定の意
味、not の意味です。非同期。それから interleaved というのは後で説明しますけれども、
交互実行と言います。これは CPU が1個しかないような場合は典型的な場合です。本当に
同時には実行できない場合です。1度に1つのコンポーネントだけが1ステップ、これは
プロセスとしてもいいですね。1度に1つのプログラム、或いは1プロセスだけが1ステ
ップだけ処理を進める。本当に2つ同時に処理が進んでいる訳ではないというのです。そ
ういう場合と、それから同期実行というのは全てのプロセス、プログラムは同時に本当に
物理的に1ステップ処理を進めるというものです。例えばソフトウェアではなくてハード
ウェア、システムだからソフトもシステムですしハードもシステムですから、ハードだと
分かりやすいと思うのですけども、ハードウェアというのはデジタル処理の場合は and と
か or とか not とかそういう論理ゲートというのを繋いでいます。それで入力を入れると、
その信号が一斉に同時に流れていって、あっちで and ゲートで and を計算中に、こっちで
or を計算しているとか、当然同時に動きます。そういうのは同期実行と言います。ハード
ウェアではそれは当たり前の世界ですけども、ソフトウェアでもそういう同期実行がだん
だん当たり前の世界になって来ているという訳です。
(5)並行システム(3/7)
今度はプロセス間の通信方法です。さっき言いましたように、複数のプログラムが全く
独立に無関係に動くのなら何も難しいことはないのですけれども、お互いに通信しながら
関連性を持ちながら全体的にシステムが状態を変化していってタスクをこなしている。そ
の場合に、通信方法として大きく分類すると3つくらいあるでしょうということです。
1つは共有変数ということで、共有メモリということもあります。メモリを共有する。
ですので、プロセッサ、CPU というのがあって、プロセッサが同じメモリ、RAM メモリ
でも良いですけど、それを共有してそのメモリを通して通信する、情報交換をするという
ことです。ですから代入文で良いということです。xに 10 を代入するということでxが 10
だということを相手に伝える。相手のプログラムはそこからxの値を読み取って、xは 10
なのかということで通信できます。普通我々の考える NTT とかが提供している通信回線を
通る訳ではないですけど、普通バスとかボードの中にある回路を通る訳です。そういう意
味である種の通信は行っています。共有変数ということで、ほんのちょっとした通信はこ
れです。
それから今度はメモリを共有しない場合です。例えばこのコンピュータと別の部屋にあ
るコンピュータといった時には、当然その RAM メモリは共有していないです。物理的に
別々な場所にあります。そういう時は直感的な意味でやはり通信線を引っ張って、通信回
線を通らないといけないのです。それは非同期のメッセージ通信と同期のメッセージ通信
という風に分かれるのですけども、非同期の方はキューを用いる。キューというのは待ち
行列という意味です。英語でスペルが難しいのですけれど queue と書くのです。キューと
いう単語があるのです。待ち行列という意味です。それとそれに対して同期メッセージは
ハンドシェイクと言いますけども、非同期の方はeメールのようなものです。携帯でも良
いしパソコンでも良いですけども、eメールを送ると相手がそこにいなくてもメールボッ
クスの中にメールが溜まっていきます。相手はいつでも良いから自分の都合の良い時にメ
ールを読んで行きます。メールが溜まっていくメールボックスが、この場合はキューと言
っているのです。そこでメッセージが読まれるのを待っている訳です。それで完全に同期
していないです。送る側と受け取る側はそれぞれ勝手に動いています。同期というのは示
し合わせて同じように協調して動くということですから、シンクロナイズということです。
シンクロナイズド・スイミングというスポーツが水泳であります。あれは見ると複数のス
イマーが協調して同じような動きをします。シンクロナイズというのはああいう概念です。
メールはそんな感じではなくて、非同期なのです。同期メッセージはお互いに示し合わせ
て通信をするということで、
「これからデータを送るぞ」と言って相手がそこにいるのを確
認して、相手が「送って良い」と言ったら「さあ送った」
、「はい、受けた」とかお互いに
協調しながらその場でリアルタイムに送っていくものです。ハンドシェイクというのは昔
からある言葉で、握手というような意味ですけども、こっち側から送る側と向こうから受
け取る側がまず事前にちゃんと握手しておいて、要するに目と目を見つめ合って、さあ行
くぞと言って通信するというようなものです。
こういうような何らかの通信方法で通信するということです。
(6)並行システム(4/7) インタリーブ
今度この絵がこれから説明するのはインタリーブということで、これも情報系の人にと
っては当然なのですけども、あまり情報のことに詳しくない人は、内部的な仕組みまで知
らなかったという人は初めて聞くかもしれないです。CPU とか本当はプログラムを同時に
は1つしか実行できない。命令を実行するプロセッサは1つしかない場合には、1回につ
いて1つの命令しか実行できませんので、複数の命令を同時には実行できない筈なのです
けども、見掛け上同時に実行しているように見えるというテクニックです。
まずプロセスAの方は、ここからスタートしてaの何らかの命令を実行して状態が変化
します。状態というのはxが3だったのが4になるとかメモリの状態が変わっていったり、
プログラムのどの部分を実行しようかという、実行しようとしている部分が変わってきた
りとか、そういうものもひっくるめて状態と言っている訳です。何か命令を実行したら、
コンピュータの状態が変わる訳です。プロセスの状態が変わる訳です。また命令を実行し
たらプロセスの状態が変わる。CPU が1個しかない場合はこの通りただ実行していけばそ
れで良いということです。こっちは別のプログラムを実行しているプロセスBです。最初
はここからスタートして、命令を実行するとこういう風に行く。ですので、プロセッサが
2つあればそれぞれプロセッサ1はこっちを実行してプロセッサ2はこっちを実行すれば
それで済むのです。ところがプロセッサが1個しかない場合は、こっちをやったりあっち
をやったりとかという風にきめ細かに切り替えながら実行していくと、そういう仕組みが
あります。そうやると、これが可能性の全体なのですけど、まず初期状態というのはプロ
セスAがこういう状態で、プロセスBがこういう状態と、2つの状態を組み合わせたのが
1つの全体としての初期状態になります。そこでプロセッサというのは1個しかないので、
aを実行するかbを実行するかどちらか1つだけしか実行できないのです。同時に実行と
いうのはないのです。aを実行し終わったら、もう1回こっちのaを実行するか、それと
もここでプロセスを切り替えて、こっちを待たせておいてここのbを実行するかです。例
えばこっちを実行してあげたとするとここになります。この後このaを実行してこのbを
実行してこういうところになるか、こっちのbを実行してこっちのaを実行してこっちに
来るかとかいう風に考えると、何通りもあります。こういうように実際は動いている。こ
ういうプロセスの切り替えとか何とかは、これを作ったプログラマはそんなコントロール
は普通あまりしなくて、OS、Windows とか UNIX、Linux とか Macintosh の OS とか、
そういうようなものがこういうようなことをある程度自動的にやってくれているのです。
そういう OS をマルチタスクの OS という風にいっています。一般に普及している Windows
のパソコンの世界では、こういうことができるようになったのが今から 14 年前、1995 年
です。その時に Windows95 というのが出たのです。この時の売りがマルチタスクなのです。
ですから Windows ですから Office のソフト等が入っていて、ワードを動かしながら同時に
エクセルも動かします。エクセルで作っている最中の表を、エクセルを終了させなくても
そのままワードに貼り付けられます。そういうことだった訳です。それ以前はそんなこと
はできなかったのです。ワープロを終わらせてファイルに入れておいて、ワープロを終わ
らせてから表計算を動かしてとか、シングルタスクの OS だったのです。Windows の世界
では 95 年、他の UNIX とか Macintosh とかは当然それ以前からそういう機能はあったの
です。Microsoft は宣伝が上手なので、一般の人がそういうこともできるのかと分かったの
が 1995 年です。
インタリーブという機能があって、自動的にプロセスを切り替えて複数個実行しますの
で、このプロセスの切り替えを目まぐるしく行えば、ユーザーから見れば本当に同時に2
つ動いているように見える訳です。例えばこっち側がゲームソフトでキャラクターを戦略
的に動かす部分のプログラムだったとして、こっちはゲームの背景でバックグラウンドミ
ュージックを流すプログラムだとすると、同時に動かすとバックグラウンドミュージック
が鳴りつつキャラクターが動くプログラムができます。あたかも同時に動いているように
見える。ですから便利なのです。このプロセスを頻繁に切り替えますので、ちょうど私達
がアニメーションで、アニメーションというのはドラえもんがこう動いたりするように見
えるけど、あれは静止画を猛スピードで1秒間に 10 何枚か切り替えているので、動いてい
るように見える訳です。1枚1枚は止まっているのだけど全体として動いている訳です。
それと同じような現象で、本当は一瞬一瞬を見ると1つしか動いていないのだけど、猛ス
ピードで切り替えたりすると、本当に同時に動いているように見える。そういうものがイ
ンタリーブというテクニックです。プロセスをインタリーブするとかインタリーブされて
いるとかそういうような言葉遣いをします。
こういうものは便利なのだけど、ソフトウェアを正しく作るという観点からすると、難
しさが出てくる訳です。それは予期できないということで、今どの経路を通るかは普通は
予期できないです。OS に任せるしかないのです。Windows の OS の中身をいくら読んで
も実際にはどうなるか分からないです。このソフトにも依存しますから、このソフトがど
ういう風に作られているかに依存するので、やってみないと分からない訳です。だからこ
う行ったりこう行ったりする。後この絵の場合は楽観的に考えてどういう順番で実行して
も同じ状態に行くように好意的に作っていますけども、もしかしたら違うかもしれないで
す。aabb と動いてきた場合のコンピュータの状態と、bbaa と動いた場合と、baba と動い
た場合と、それぞれここに至る時には本当はちょっと違った状態になっているかもしれな
い。そういうこともあるかもしれないです。それが予期できない訳です。
それからほとんど同じことですが、制御できない。こういう風にしていると、ここは必
ず abba の順になるようにプログラムを書いておこうなどというのは、なかなかできないで
す。
それから今度は膨大な数の実行経路を生じる。予期できないのでどうなっても良いよう
にプログラムを作っていく必要がある訳です。ですけども、どうなっても良いといっても
その数が膨大なのです。ここは授業のために2ステップしか書いていない訳ですけども、
まともなプログラムは本当はずっと長い訳です。こっちももっと長いのです。この絵もも
っとでっかいダイヤモンドの形になります。こういうマス目が無数にたくさんある訳です。
それがこういった場合とかこういった場合とかなりますので、何通りになりますかという
のが組み合わせの問題で、簡単な大学入試問題くらいにもできるかもしれないですけども、
そういう組み合わせの数だけ実行経路が生じます。
それからaとbの作っているプログラマが全然違うかもしれないです。こっちが我が社
のプログラマであっちは誰が作ったのか分からないオープン・ソースのプログラムなのか
もしれないので、両方が示し合わせてではこうしましょうとプログラムが作れる訳がない
のです。ですからこれは我々にとってもコントロールできないので、どうなってもちゃん
と動くようになっているかどうか、そういうようなことを検証しないといけないのです。
そういう風に作っておく。そしてそれは本当にそうなっているか自信を持たないといけな
いのです。そういうところに難しさがあります。
(7)並行システム(5/7) 相互排他
次の問題が相互排他、mutual exclusion ということで、2つのプロセスA、Bがあって、
何かを共有している、この場合は変数を共有していることになっていますけれど、さっき
私が話した例ではここはプリンタを共有しているとかと言います。何らかの意味で何かを
共有している。物理的リソースでも良いし、情報的なリソース、そういう資源でも良いで
す。その時に自分だけが唾を付けて自分だけが使いたい、相手に使わせたら大変なことに
なるという状況があるのです。そうしないといけない場合があるのです。これは mutual
exclusion というのはそういう意味で、排他というのは相手を除外するという意味です。
mutual というのはお互いに。自分も除外されるかもしれない、自分も相手を除外したい、
そういうようなことからそういう言葉が出てきた。
この例では、プロセスAとBがメモリを共有して通信をしている、コミュニケーション
をしているとします。現在メモリの中のmという変数が 5000 であるとします。プロセスA
はC言語の代入文で現在のmの値、5000 ですけど、それに 1000 を足した 6000 をまたmに
書き込みたいと、これを 6000 にしたいと言います。で、こっち側はその反対のようなもの
で、現在のmの 5000 から 1000 を引いて 4000 にしてそれをmというここに書き込みたい
という風になっているとします。
それでC言語レベルのソフトウェアしか知らない人はちょっと理解しにくいので、ちょ
っと機械語まで入ってもらわないといけないのですけども、そんなに難しいことではない
です。C言語でこう書いたら、これはコンパイラというもので機械語という命令に置き換
わります。その機械語というのは1つの代入文が1命令になる訳ではなくて複数の命令に
なるのです。機械語というのはほんのちょっとのことしかできません。それで典型的には
こんなようなものになるのです。こういう具体的な MOV とか ADD とかそんなのはあまり
知らなくて良いです。何をやっているかを分かってもらえば良いです。最初の機械語では
こんなように、アセンブリ言語と言いますけど、これをさらにアセンブラというのでコン
パイルすると 01 という機械語命令になるのです。011011 とか、16 ビットくらいのものに
なるのです。これはmという番地のこの変数の値を、Aレジスタと言います。コンピュー
タの CPU というところにレジスタというのがあります。それもメモリですが高速なメモリ
です。A、B、Cという風に普通名前が付いているのです。mというのは番地なのでここ
が 1000 番地とかそういう意味です。その番地の内容をコンピュータの内部の CPU のAレ
ジスタというところに持ってこいという MOV、データを移動しなさい、コピーしなさいと
いう命令です。それによってここのm、これは CPU でこれはメモリで、メモリは別途あり
ます。CPU というのはまた別な IC です。この間には普通バスとか何とかやはり簡単な通
信回線があるのです。ここのmの値をこっち側に持ってくるという意味です。絵に描いて
いませんけれど、Aという場所があってそこに 5000 というのを持ってくるという意味なの
です。ですからAが 5000 になります。それで足し算を行うのはレジスタ同士の足し算とか
そういう風に普通の機械はなっています。Aに持ってこないとそもそも足し算できないの
でそういうことをするのです。Aに持って来たのでやっと足し算できますということで、
Aに 1000 を足し加えなさい、6000 にして、足した結果は普通Aに置き換わったりするよ
うな命令になっていることが多いです。ですからそうだとすると、Aが 6000 になります。
それでこれで計算が終わりましたので、これをmに戻さないといけないので、MOV 命令で
Aとmを逆にすると、Aの内容をmの方に移動しなさいということで 6000 がここに書き込
まれるという、こういう少なくとも3ステップが普通必要です。こっち側の引き算も全く
同じことで、mの内容をBに持ってきて、それからBレジスタです。Bレジスタの中で 1000
を引いて 4000 にして、その 4000 をmに書き戻してmが 4000 になる。こういう風になっ
ています。
これをほぼ同時に実行している。それぞれ全然別のタイミングで実行すると、全然問題
ないのです。これがほぼ同時に実行された場合で、こういう順番でインタリーブされたら
どうなるかということです。これが例えば何万回に1回くらいこういうことがあるかもし
れないです。その時には変なことが起こるのです。こっち側でデータを読み取って足し算
したのですけど、これを戻す前に戻す前の 5000 をこっち側に読み取って引き算しているの
です。だからこっち側では 6000 になっていて、こっち側では 4000 になっていて、それか
らデータを戻し始めると、まずmは 6000 になるのだけどその直後にmは 4000 になるとい
うことで、ここが 4000 になります。全然別なタイミングでやると、これは 5000 の筈です。
どっちが先にやろうとも一方では 1000 を足して一方では 1000 を引くのだから、両方1回
ずつやればこれは 5000 のままに戻ります。ですけどこれはそうならないです。4000 にな
ります。そういうことが起きたりする訳です。これはほぼ同時にお互いのリソースを2人
で共有して、勝手にこう使ったからです。だからこれは自分だけしか使わせないと、1、
2、3ステップを纏めてやらせてくれという風に纏めて使うようにしないといけないです。
それを簡単に表したのがこういう、ちょっとアニメーションで説明をしたいと思います。
これ銀行なのです。銀行に 30 万円の預金口座があるとして、お母さんが子供のためにこの
銀行にお金を振り込みたいと、それで 10 万円仕送りするとします。ですから 30 万に 10 万
円足そうとする訳ですけど、今の話でまず 30 万というのはこっち側にコンピュータを持っ
てきて足し算するというようなことだったので、そういう風になっているとします。40 万
を足して、ここに 40 万としたい。これがお母さんの意図なのです。子供の方はその 40 万
から 10 万を引き出して使いたいというので、これは 30 万になってこう。元々あった 30 万
はそのままになる。そういう話だったのです。
それでその後私が言ったのは、預け入れと引き出しがほぼ同時の場合に、変なことが起
こるということで、まずお母さんが 10 万円足して 40 万円にしたほぼ同時に子供がお金を
引き出すと、20 万円になってしまったと言って、お母さんは 40 万円にしましたよと言った
けどこっち側は 20 万円なので、30 万あってお母さんは 10 万振り込んだのだけど 20 万円
になっている。そういうようなことです。
(8)並行システム(6/7) デッドロック
次の問題はデッドロックということで、暗礁に乗り上げるというような感じの言葉なの
ですけれども、やはりプロセスA、Bという2つのプロセスがリソースを共有している場
合に起きます。このリソースはさっきと同じで変数でもメモリでも良いのですけれども、
今回ちょっと雰囲気を変えて周辺機器ということにして、スキャナーとプリンタをネット
ワーク経由で共有しているとします。AとBのやりたいことは同じで、スキャナーに紙を
ピッと入れるとそれをスキャンして、それをプリンタに出す。ですからコピー機代わりに
する、コピー機を買うのが面倒臭いからスキャナーとプリンタというのを買っておいて、
コピーする時にはコピーソフトを使ってスキャナーの中に入れたものを、ぴゅーっとプロ
グラムが読み込んでプリンタに出すようにする。ということをどっちもやりたいとします。
当然これは今説明した相互排他というのをやらないといけないので、勝手に同時にプリン
タにデータを流してもしょうがないです。2つのやりたいことがまぜこぜになってプリン
トされてもしょうがないです。スキャナーも2つの物を同時にスキャンすることはできな
いので、相互排他をしないといけないです。何らかのテクニックでするのは当然できるの
で、そういうようにスキャナー、プリンタは自分しか使いませんと、相手は使えないとい
う仕組みをもうちゃんとできたとします。それでもう問題がないかというと、デッドロッ
クという問題がさらにあるという、そういう問題です。
それでプロセスAがどういう風になっているかというと、この3つの命令を実行します。
今度は機械語命令ではなくて、一固まりのモジュール、関数みたいなものです。まず acquire
Scanner ということでこれはスキャナーを取得すると言います。他の人が使えないように
予約する、今度は自分の番だと他のものは使うなということに成功したとします。その次
に acquire Printer、プリンタもこれから自分がぜひ使わせてくれと予約をして、予約済み
になっていると、他の人は使えない状態になったとします。それから Copy というやりたい
ことをやるのです。スキャナーでビーッと読みこんでプリンタにコピーするプログラムが
動く。これは何も問題ないです。それからプロセスBの方もあるのですけれども、こっち
もほとんど同じことをやるのだけれども、作ったソフトのメーカー、プログラマがちょっ
と違っていて、最初にプリンタに唾を付けたと。プリンタをまず確保せよということで、
それに成功したらスキャナーを確保せよと。両方確保されたらコピー作業終了と、こうい
うプログラムになっているとします。これも全然問題ない訳です。完全にこれは排他制御、
相互排除しています。それでもデッドロックが起きるということです。この順番に起きる。
まず最初にプロセスAがスキャナーに唾を付けて自分のものだと言います。時間的にそ
の直後にプロセスBが動き始めて、プリンタを確保します。それでその次に進もうとする
のですけども、どっちに行くか分からないです。仮にこっち側が今度動き出して、プリン
タを自分の物に予約しようと思っても、もう予約済みなのです。ですからプロセスBがプ
リンタを使い終わるまで待たないといけないので、プロセスAは仕方ない、少し待とうか
というモードになる訳です。そうこうしているうちに、今度こっち側が動きだして、スキ
ャナーを取得しようとします。しかしスキャナーはもうこっち側で予約済みなので、これ
が使い終わるまで待つので、待ちモードになる訳です。これはお互いに待ちはいつまで経
っても解消されないです。お互いに相手が使い終わるのを待っている訳です。両方揃わな
いと動かない訳です。ですからそういう状態です。これは簡単な例題ですけど、一般にリ
ソースを共有していて、お互いにその1部分だけを取得していて、お互いに相手が使い終
わるのを待っているという、そういうループ状態です。AはBを待っていてBはAを待っ
ている。或いは第3者が入ってくるかもしれないです。複雑な状況ではAがBを待ちBが
Cを待ちCがAを待つということもあり得るのです。そういうようにしてお互いに待って
いてそれ以上動かない状態、それをデッドロックと言います。ということでこの時点でデ
ッドロックになってこれ以上進むことがない。
そういうことなので、ソフトを作る時にはデッドロックを絶対起こさないようにソフト
ウェアを作るか、或いはデッドロックが起きるかもしれないことは許すのだけれども、も
し起きたらこうしようと、デッドロックを検知するモジュールを別途作っておいて、もし
デッドロックだったらこういう回避策、こういう風にやり直そうとか、何らかの対策が必
要です。デッドロックをなしにするか、デッドロックを許すけれどデッドロックが起きた
後の対策をちゃんと練ってあるかです。そういうようにシステムを作る必要があります。
(9)並行システム(7/7) ライブロック,飢餓
その次、最後ですけれども、ライブロック、或いは同じ概念なのですけれども、言葉と
して飢餓、starvation という言葉で呼ばれることもある現象です。やはりこのプロセスA、
B、C、複数のプロセスが1つのリソースを共有している場合に起きます。
この例ではA、B、CのうちCの優先順位が低いとします。だから同時に競合が起きた
時には、Cは後回しにされると、実際のシステムでもそういう風になっている訳です。例
えば実際のこのコンピュータで1番優先されるのは、例えば電源が停電して急に落ちたと
いうことを感知したら、現在のメモリの状態をハードディスクにセーブしないと消えてし
まいます。ですからこれが OS の中で優先されます。停電が起きたという風にコンピュータ
の CPU が感知してから、本当に電圧がぐっと下がるまで何ミリ秒か時間がありますので、
例えば1ミリ秒くらい時間があれば、1ミリ秒もあればコンピュータはかなりの仕事がで
きるのです。その間に電源が落ちた場合のことを想定して、大事な情報をハードディスク
にセーブすることができます。それが最優先になります。それからどうでも良いようなプ
ロセス、ユーザーが趣味で作っているプログラムとか、そんなようなのは優先順位が低い
とか、OS の中でもちゃんとそんな風に管理されているのです。そういう風になっていると
して、リソースを排他的にやはり使いますので、自分のものに使いたい、自分が優先的に
使いたいという request を出します。それでそれが許されたら、acquire、取得する、実際
にそれを使うと。これが1ステップです。また何かいろいろなことをしてまた request して
また acquire。request、acquire が1ペアで、それが何回も何回も行われる。そういうプロ
グラムになっているとします。そうすると、まずお互いに request を出すのですけれども、
これが request して acquire するとプロセスBが request してもちょっと待つことになりま
す。それでこっちが使い終わるとやっとこっちが使えるという風になるのです。プロセス
Cは優先順位が低いので request してもしばらく使えないのです。AもBも使い終わるのを
待たないといけないのですけども、AとBが使い終わってやっと自分の番だなと思ったら、
その時にはもうまたAの request が入っていたというので、またAが使うことになるのです。
そうこうしているうちに、またBが request して取得するということなので、いつまで経っ
てもAとBが交互に頻繁に使うので、自分の番が回ってこないということがあるのです。
普通にただプログラムを作るとそういう風になるのです。そうするといくら優先順位が低
くてもこれでは大変です。
プログラムが凍ってしまって動かないという状態がよくあると思うのですけれども、そ
れは例えばこういう時なのです。或いはデッドロックかライブロックの時に、「あれ何だ、
どうしたんだ、動かない」という時がある。どっちかなのです。こういうことがあっては
いけないです。優先順位が低いですから、かなり待たされるのはしょうがないのだけど、
いつか必ずちゃんと動くようになってほしいということがあります。
それで仮にこういう風になって、こういうことがずっと無限に続いて、プロセスCは決
して資源を獲得できないということが分かったとします。そういう場合にこのプロセスC
はライブロックされた、ライブロックに陥ったという風に言います。その場合デッドロッ
クと微妙に違うのは、雰囲気が違いますが、後お互いに相手を待ってお互いに身動きが取
れない状態ではないのです。一生懸命お互い全部動いているのです。これとこれとこれも。
だけども優先順位の低いものはそれ以上進めなくなっているという訳です。ですからこの
リソースが食べ物だとすると、プロセスCは食べられないので飢餓してしまう、死んでし
まう、餓死してしまう。それでこういう starvation という言葉が付いています。
それでこういうライブロックとか飢餓が起きないものを公平性があると言います。この
絵の場合はライブロックが起きているので公平性がないのです。こういうことが決してな
ければ公平性があると言います。fairness、フェアだと言います。優先順位がちょっと低い
くらい大丈夫なのです。公平性がある訳です。これも間違えやすいのですけれど、公平性
があるというのは優先順位が同じということではないのです。この世界は優先順位がある
のは当然の世界なのです。さっきの停電の時の処理とお遊びのプログラムでは当然違いま
す。扱いが違うのは当然であって、それは公平なのです。公平性がないというのはこうい
う死んでしまうプロセスあったら公平性がないのです。かなり待たされても必ずいつかち
ゃんと動き出すなら、公平性があるのです。OS の中でちゃんと公平性のあるようなスケジ
ューリングとかそういうことを作っておかないといけないということです。こういう風に
並行システムではいろいろな問題が生じることが分かったと思います。
(10)2.モデル検査
次はそれを解決するためにモデル検査、解決するという訳ではないけど、本当にちゃん
と変なことが起きないかどうか検査する。起きたら起きたでまた何か対策を取らないとい
けないです。これは検査するだけのシステムですけども、そういうような話をちょっとし
ます。そもそも何なのかという概略です。まず最初はそもそもモデル検査というのは何な
のかという雰囲気の話をします。それでこの場合プログラムは有限状態システム、これは
我々エンジニアにとって馴染みがある状態遷移図のようなものです。そういうようなもの
で理論的にモデル化されますので、それをちょっと話して、それでどういうことが検証で
きるのかと、何でもかんでもできる訳ではないです。そういう話をします。
(11)モデル検査とは何か
まずモデル検査ですけども、英語で model checking という風に言います。何らかの性質
をチェックするということです。成り立つか成り立たないか。そういう意味で model
checking。最近はこういう技術がソフトウェアの世界でよく知られてきたので、モデルチ
ェックというのは動詞のように使われるのです。チェックというのは元々動詞です。何々
をチェックする。だけどモデル検査するという日本語で、モデル検査するに相当する動詞
ができて、それをモデルチェックというのです。私はそのシステムをモデルチェックした
と言ったら、I model check the software.とか、そういうように言います。それはプログラ
ムというのもいろいろな機械語があるのでちょっと抽象化して、状態遷移図のように有限
状態並行システム、finite state concurrent systems と書きましたけど、普通の状態遷移図
です。大事なのは有限だということです。無限だったら機械的にチェックしきれないので、
状態数が有限の状態遷移系です。そういうものの検証、あることが成り立つか成り立たな
いかということを、変なことが起きないかということを検証する。それを自動的に行うの
です。そういう技術を model checking と言います。
対象となっているのがここに書いてあります並行システムですので、さっき説明したよ
うに、複数のプロセスが並列又は擬似並列に動作をするものです。そういうものを対象に
します。ですから逐次的な1本のプログラムにモデル検査をしようと思っても、全く無意
味なのです。で、有限状態システムというところが大事で、ここのところです。状態数が
有限個なのです。それで状態がいろいろ遷移していきます。そういうシステムを対象にす
るので、状態数が無限個あるというものは対象になりません。後、我々の有限のメモリを
使って実行するソフトウェアというのは、理論的には当然有限なのです。例えばこの整数
を扱う時に数学の概念で整数と言ったら無限個あります。だけど使うのが integer、int 型
だと言ったら有限個しかないです。int というのはせいぜい 32 ビットとか、long int だった
ら 64 ビットの世界です。だから理論的には有限なのですけれども、現実問題として同じ有
限でもすごく膨大な有限はあっても無限に近いような有限は事実上できないです。そこそ
この有限状態でないと現実にはできないです。そういう制約があります。
それから検証というのは何かチェックするという意味ですけど、何をチェックするかと
いうと、期待される性質、こういうソフトウェアを作ったのだけど、これはデッドロック
は絶対起きませんとか、必ずこういう風になっていますとか、そういうことを想定してこ
うなる筈だと思ってソフトを作っている訳です。でも本当にそうなるかどうかは誰も分か
らない訳です。それをソフトウェア的に自動的に確認するというのが検証です。それでこ
の性質のことを仕様とも言う場合もあります。英語で性質は property です。仕様は
specification。英語でも別な単語ですけども、どちらかというと性質の方が誤解がないと思
います。ソフトウェアの全ての仕様を全部満たすことを確認するというのは大変なことで、
あまりそういうことはできない。仕様の一部です。こういう性質があるとか言います。特
に重要な性質をいくつかピックアップして、そういうものは検証できるということです。
(12)状態遷移系(オートマトン)
そこで出てきた状態遷移系と言いますけども、ソフトウェアというのは結局のところ、
コンピュータの状態がいろいろ変化していくことをコントロールしているのがソフトウェ
アです。だから突き詰めていくとこういう状態遷移図になってしまう訳です。コンピュー
タ・サイエンスの分野では、こういうようなものと敢えて曖昧に言っておきますけども、
この種のものをオートマトンと言って、いろいろな種類のものを研究しているのです。そ
ういうようなものを説明します。
単なる例で説明します。我々エンジニアなのでこんなものはいくらでも見たことがある
と思うので、こんなものを見たことがあるでしょうくらいの説明なのですけども、この例
は4進カウンタ、これはソフトウェアではなくてハードの世界です。システムというのは
ソフトでハードでも同じなので、簡単なのはハードなのでハードで説明します。2ビット
で0、1、2、3という4つの状態を取ります。それでカウントする。ですから1、2、
3、4、と4つカウントしたら信号が出るというようなハードウェアを想定します。そう
すると状態が4つある訳です。ここがここの組み合わせで 00 というのと 01, 10, 11 と4つ
あります。これが4つです。想定しているのがこれが0、これを2桁の2進数と見た時に、
0、1、2、3になるように状態に割り付けるのです。初期状態、工場出荷した時にはこ
こが 00、状態0になっているとします。そして外部から1だけカウントアップしなさいと
いう tick という信号が来る。外部からのイベントが来るとします。そうすると状態が1に
なる。また tick が来ると状態が2になって、また tick が来ると状態が3になって、また tick
が来ると状態がリセットされて0になる。これが基本動作ですけども、外部からは reset 信
号というのが来ることがある。その場合はどういう状態であっても reset 信号が来ると状態
0に戻る。ですから状態0の時も reset で0です。そういう簡単なシステムを考えています。
それでここからがちょっと普通とは違うところなのですけども、モデル検査というのは
論理学的な理論をベースにしていろいろ作っている技術なので、ちょっと論理学が出てき
ます。ここは1とか0なのですけども、ブール代数とかで1は論理的な真と見做したりし
ます。0は偽です。true、false と見做してこれを命題だと言います。こっちの命題をp、
こっちの命題をq。10 と見ても良いし、true・false として見ても良い。そういう風に考え
るので、システムの状態はこういう複数の命題の全体が真だったり偽だったりすることで
状態を表します。そういうような理論になっています。そしてこの状態の中に真のものだ
けの命題だけを書き込むことにします。状態0というのは 00 ですので、pもqもどちらの
命題も0、つまり偽です。ですから真の命題はないので書いていない。それで tick が来た
ら 01 になるので、pという命題が真になります。ですからここにpと書いてあります。q
は偽のままなので書いていない、という風に何か外部から信号が来ると今まで命題が真だ
ったものが偽になったり、偽だったものが真になる、そういうような議論になっています。
また今度 tick が来ると状態が2進数の2だから 10 になります。そうするとqが真でpが偽
ですからqとだけ書きます。また tick が来るとここにあるような 11 になるので、どちらも
真になります。また tick が来たりリセットしたりすると、ここになる。ここがちょっと普
通ではないところです。あまり本質的なことではないですけども、こういうことをやった
研究者はこういう風に理論を構築しているのです。
ということでこの状態遷移系というのはどういうものなのかというと、こういう4つの
情報を表しています。典型的にはこういう絵で表すのです。別に絵で表さなくても良いの
ですけど、まず状態の有限集合だということです。この場合状態が4つあります。4とい
うのは有限です。状態の有限集合です。それからもしグラフ理論というのを知っている人
がいたら、これはある種のグラフ、点と線からなっていると、或いはノードとエッジから
なっているというと思うのですけど、こういうノード、丸です、丸の数が有限個だと言い
ます。それから初期状態の集合というのは事前に決めていないといけない。どこからスタ
ートするか分かりませんというのは駄目なのです。それを決めておきます。普通は初期状
態1個なのですけども、場合によっては初期状態が2、3個あっても良い、集合でも良い
ことにします。それから遷移関係というのは、グラフ理論で言うとこの矢印の情報です。
何と何が繋がっていて、どういうイベントが来たらどっちに行くのかということです。そ
ういうことが分かっているのです。そういう情報を遷移関係と言います。それから各状態
ごとのラベル。状態をただ丸だけで書いたら区別できないので、何か区別するために0、
1、2とか名前を付けないといけないです。その時に理論的に都合が良い名前を付けてお
くと良いと思います。ここに太郎、花子とかという名前を付けても理論的に便利とは思え
ないです。それで各状態ごとのラベルとして、こういう命題の真であるものをラベルとす
る、真である命題の集合を以てこのノードの名前とするという風に普通はしています。そ
ういうようなラベルの情報です。ラベルとは各状態に付ける名前のことです。そういう情
報が、この4つの情報が合わさったものが、状態遷移系です。簡単に言うとこういう図の
ことを言う訳です。4つの情報が揃っていれば良いので、言葉で書いても良い訳です。で
も普通我々エンジニアは言葉では書かないで絵で描くというだけです。だけどこのノード
は 100 万個もあったら絵では描けないから、
言葉で書かないといけないかもしれないです。
そういうものを状態遷移系と言います。
後重要な概念としてさっきの tick とかに相当するのがイベントです。外部から来るので
す。外部から来るものは我々は普通制御できないと考えます。状態1の時に tick が来るか
reset が来るかは我々プログラマがコントロールできるものではないです。どっちに行くか
分からないという風に解釈します。それからさっきから言っているラベルです。状態の名
前はその状態で成り立つ原始命題、原始命題というのは最初に付けた原始的な命題、複雑
な命題ではないです。and とか or とか難しいものは入っていない、原始命題の集合でラベ
ルを作ります。それから後現実問題として状態数有限で良いと言ったけど、どれくらいな
のかというと、これは今後技術が進歩するとどんどん変わっていくと思うのですけれども、
大体現時点 2008 年とか 2009 年とかで、いろいろこういうことをやっている研究者の発表
を見ると、その内容にもよるのですけれども、数百万くらいまでは OK というレベルです。
ですから状態数が1億個あったらできるかどうかはちょっと分からないです。状態数が1
万くらいなら確実にできるかと思います。そういうところです。
(13)検証できる性質(1/3)
次は検証できる性質としてどういうものがあるあるかということです。これも理論的に
言ってしまえば、何かすごい訳の分からない話になるので、ユーザーから見てどういう性
質が検証できるのかという説明にします。
2つあるのですけど、まずは安全性というものです。safety と言います。これは一般的
には「悪いことは決して起こらない」という性質です。ちょっと広く捉えてください。安
全というのは生命に危険があるとか、そういうようなことがあると思うのですけど、必ず
しも生命に危険とかそういうことではないです。とにかくシステム設計者にとって都合が
悪いことが起こらなければ安全というくらいのもので考えてください。ですからこれは逆
に言うと良いことは常に成り立っている、だから悪いことは決して起こらないということ
です。そんな雰囲気の性質です。それを検証できるという意味です。それを safety と言い
ます。
もう1つは活性、liveness というので、
「良いことはいつかは成り立つ」という性質です。
安全性というのは、悪いことは決して起こっていないから、良いことが常に成り立ってい
ます。活性の方は微妙に違うのですけど、良いことはいつかは。常にというところがいつ
かはになっています。いつかは成り立つという性質です。ちょっと safety とは違います。
良いことは今は成り立っていなくても良いのです。今成り立っていなくても良いのだけど、
いつか必ず成り立つ、いつまでも成り立たないということはないということです。さっき
の starvation のところで餓死して死んでしまうプロセスがありましたね。あれは悪いこと
です。良いことというのはちゃんと皆が生きて食べていける。いつまでもかなり待たされ
ても良いからいつかはちゃんと食べることができるというような性質です。それが liveness
と言います。
ここで非常に曖昧な説明をしましたけれど、ここで言う悪いこととは何かということで
す。それから良いことは何かというのは、システム設計者が判断して解釈すれば良いので
す。ですから一般にはこういう理解で普通は充分だと思います。後、この「常に」と「い
つかは」というところを見て薄々想像できることは、しかも私はさっきから論理学をベー
スにしているとか言いました。常にとかというのは、常に、always ということで数学で言
う任意のとかを連想します。任意の何々に対して任意の時点で常に良いことをしている。
いつかはというのは論理学で言うと何々が存在する。任意のというのは数学の記号でAと
いうのを引っくり返したような記号(∀)です。何々が存在するというのはアルファベッ
トのEを引っくり返したような記号(∃)です。ある何々が存在してとかそういう意味で
言うと、いつか将来ある時点が存在してその時にこういうことが成り立っているというこ
とを連想すると思うのですけども、もしそういうことを連想した人がいたらすごい直感が
鋭いです。実際にそういう風になっている。そういうことを論理学的に作り出しているの
です。それをまた後でちょっと説明します。
(14)検証できる性質(2/3)
ちょっとした例を挙げますけども、まず安全性です。悪いことは決して起こらないこと
の例として、先程説明したデッドロック、暗礁に乗り上げて動かないというようなことは
悪いことですので、それが決してデッドロックしないかどうかを検査できます。それから
これはこの授業のスライドを作っている時にたまたま実際に世の中で起きた事件なのです
けども、エレベータのドアが開いたままエレベータが動き出して人が死んだという事件が
あります。それは悪いことなので、安全性とはそのエレベータはドアが開いたまま昇降す
ることは決してないという性質です。それをチェックできます。これは本当に人間の生死
に関わる本来の意味の安全という意味です。
それからこのメッセージは暗号化されずに送信されることは決してない。複雑なソフト
ウェアを作っておいて、いろいろなメッセージがあちこちから出てきてそれをくっつけた
り切ったり貼ったりして、いろいろなケースがあると思うのですけれども、どんな場合で
も必ず暗号化して送信することにしているつもりだったとします。だけどバグがあったら
そうではない訳です。そういう悪いことは決してないとか、そういうような性質です。
(15)検証できる性質(3/3)
それから活性の方。良いことはいつか必ず起こるということの例として、資源を要求し
たらいつか必ず取得できる。もう資源というのは抽象的に考えてほしいのですけれど、さ
っき出てきた例ではメモリもそうです。メモリは複数のプロセスで共有していますので、
自分がいつでも勝手に使える訳ではないです。相互排除しています。それからプリンタと
かスキャナーもそうです。そういうような情報的な資源、ハードウェア資源です。そうい
うようなものを要求したらいつか必ず取得できるということです。
それからもっと目に見えるものとして、OK ボタンをクリックすると、いつか必ずそれに
対応した動作をする。何か変なアプリケーションだと OK ボタンを押したのだけど、いつ
までも返事が返ってこない等ということもあります。それは活性がないというのです。で
すから、他にどんなプロセスが動いていても、自分の作ったそういうグラフィカル・ユー
ザー・インターフェースのモジュールは必ずこういう性質を持っているとか、そういうよ
うなことです。それからこのメッセージは必ず宛先に届く。メッセージの送信、これと似
ていますけど、送信ボタンを押したとか、GUI ではなくて送信のための関数を実行したら、
必ず本当に相手に届くかということです。本当に届けばそのシステムは活性があるという
ことです。我々メールソフトはこういう性質を持っていると信用しているので、送信ボタ
ンを押したらそのままにしています。相手に届いた筈だと、本当に届いたかと別途電話し
たりしないです。こういう性質は非常に重要なのです。
(16)3.モデル検査の実施
次にそういうモデル検査を実際に実施する話です。今日の時点ではモデル検査というの
はかなりブラックボックスに近いですけど、一体それはいつ誰がどう行うのかとかそうい
うことです。それは実際の生産現場でソフトウェアがどういう考え方で作られているかと
いう、そのライフサイクルというソフトウェア工学の教科書の最初の方に出てくる話をし
ておかないとならないので、そういう話をします。ではいつ誰がやるか分かったとして、
どうやってやるのですかというそのモデル検査の実施手順の話をします。それから最後何
故ということで、何故モデル検査をやるか、他にもこういう方法があるのではないかとあ
ると思うのです。何故モデル検査なのかということを簡単に話します。
(17)ソフトウェアのライフサイクル: When & Who
まずそのソフトウェアのライフサイクル。ライフサイクルとは一生ということで、ソフ
トウェアが生まれてから死ぬまでの一生ということです。で、これはソフトウェアの専門
家ではない人が話を聞くと、ソフトウェアの一生と言われてもピンと来ないかもしれない
のですけど、ソフトウェアも生まれてから死ぬまでの寿命があるのです。生まれるところ
はどこから始まるかというと、こういうシステムを作りたいという要求から始まるのです。
それは我々エンジニアからとは限らずに、普通の一般社会の人達、官庁の人とかどこかの
メーカー、企業の工場の人とかビジネスをやっている人とか、そういう要求から始まりま
す。一体それを情報システムとするには何をやれば良いのかと分析をして、そういう要求
する人と一緒にソフトウェア技術者が仕様書を作ります。今度それを実際に動くシステム
とするために、設計をします。例えばどういうプログラミング言語で作ったら良いかとか、
どういうアルゴリズムを使うかとか、どういうモジュールで作るか、オブジェクト指向だ
ったらどういうクラスを作れば良いかとか、そういう設計をして、設計書をいうのを作り
ます。その設計書に基づいて下にコーディングします。それを実装と言います。これは大
きな会社だったら下請けのソフトウェアハウスとかに任せればプログラムを作ってくれま
す。それでコードが納品されますので、それは下請けには任されなければ自分でテストし
ます。これで良ければ製品化する。これで一旦終わったかに見えるのですけど、ユーザー
に渡って使ってもらっているうちに、バグがあったりとかもっとこうしてほしいとかとい
うので、また一部分ここに戻ってくるのです。こういうのがぐるっと繰り返されるのです。
ソフトウェアはこういうような一生を送る訳です。いつまでも回っている訳ではなくて、
もう古くなって使えなくなる。ビジネスの状況が変わって来たとか環境が変わって来たと
か、もっとすごいアルゴリズムが出たとか、ソフトウェアというのは大抵の場合5、6年
もしたらそんなものは使わないです。それでソフトウェアの寿命が終えるという風になっ
ています。
それで今 model checking という、そのモデルという言葉があります。モデル検査です。
そのモデルを検査する訳です。このモデルというのは設計の段階で作られます。まずこの
要求分析の仕様書、大抵は日本語とか英語とかいう言葉で大体は書かれるのです。或いは
簡単な図とかです。この設計の辺りになると、もうちょっと動かすためのもうちょっと詳
細化したものにするのですけども、だからと言ってプログラムを書いてしまう訳ではない
です。プログラムのコードを書くのはここですから。だから要求とプログラムの実際のコ
ードとの狭間の間にあるものは、最近ではモデルと呼ばれています。このモデルを記述す
るための言語ということで、UML、Unified Modeling Language とか言います。何か適切
な言語とか図で作るものなのです。そのレベルのものをモデルと言っています。それを検
査するということですので、いつ誰がモデル検査をするのかというと、いつというのはこ
のモデルを作った時です。モデルを作った時誰がやるのかというと、この設計者がやる訳
です。自分の設計したモデルがちゃんと正しいかどうかを検査するというのが答えになる。
ですからプログラマがやる仕事ではないです。それからお客さんというか要求する人がや
る仕事でもないです。この辺りをやるのは普通システムエンジニアと言われています。こ
っちはプログラマです。こっちはクライアントです。ですからシステムエンジニアがやる
のです。
(18)モデル検査の実施手順: How
次どのようにやりますかということですけど、次の3つのステップでやります。
まずモデリングということで、これはシステムエンジニアがやる主要な仕事です。要求
を突きつけられたらどういうソフトにすれば良いかというモデルを作ります。そうしたら
今度は性質を記述します。自分の作ったこのモデルで情報システムを作ると、ちゃんとこ
ういう動作をしてこういう性質が満たされる筈です。さっきのこういう悪いことは絶対に
起きないとか、こういう良いことはいつか必ず起きるように作ってあるとか、そういう重
要な検証したい性質を記述します。ですから何から何までソフトウェアの仕様を書く訳で
はないです。仕様は既にありますので、重要な検証したい性質を記述します。そしてそれ
を検証する。モデルチェッカーというソフトウェアを使って検証するということです。
(19)(1) モデリング
まずそれぞれ説明しますけど、まずモデリングです。これは自分が作った設計内容をモ
デル記述言語で記述します。よく知られているのでさっき言いました UML というモデル記
述言語があるのですけども、モデル検査の場合はあれでは駄目です。別な言語でモデルを
記述します。モデルというのは結局のところ、コンパイルという訳ではないけど、変換し
て状態遷移系、さっきの状態遷移図のようなものに直接変換できる程度のもののことを言
っています。
モデル記述言語というのは実際どういうものがあるか。モデル検査のためのモデル記述
言語です。まず見掛け上C言語風に似ているものがあります。C言語を知っていれば簡単
に覚えられそうなものです。モデル検査のシステムで SPIN というのがあり、後でまた簡
単に紹介します。ここでは Promela 言語というものを使っています。SMV とそれをバージ
ョンアップした NuSMV というのは、言語には何々言語という名前が付いていないのです
けど、そのシステムで用意した特別な言語があります。それから全然別な考え方に基づい
て、理論系の方で複数のプロセスがどう動くかというのはやっぱり数学的にモデル化でき
るのです。そういうのをプロセス代数と言いますけど、それに基づいた言語が FSP、シス
テムの名前は LTSA と言います。Label Transition 何だかといって、これは Finite Single?
何とか Process だったか、Sequential Process だったか。そういうものが他にもいろいろ
あるのですけれども、そういう特別な言語でモデルを記述する。ですから状態遷移系を記
述するのですけれども、お絵かきソフトでさっきの丸とか矢印とかを一生懸命描くという
のは、あまりないです。あれだと 100 万個の状態を記述できないです。こういう言語を使
うと、100 万個くらいの状態をパッと記述できたりします。
(20)(2) 性質の記述
次に性質を記述するのです。満たすべき性質、こういう悪いことが起きないというプロ
パティの記述もやはり言語で記述をします。記述には一般的に時間の概念を表します。時
間のタイミングが非常に重要なのです。同時にこういうことが起きるとか、いつか必ずこ
ういうことが起きるとかです。それで通常の論理学では and とか or とか not とかそういう
ものを当然使うのですけれども、その他に時間の概念を表すもので普通の論理を拡張する
のです。それを時相論理という風に言っています。Temporal Logic というのですけれども、
時相というのは時間の、時間に関するというような意味です。それで実際によく知られて
いるものが2つあるのです。全然違うものではなくて大体が共通しているのですけれども、
CTL、Computation Tree Logic というのと、LTL、Linear Temporal Logic というのが知
られています。時相論理というのは Temporal Logic というこの英語を日本語にしたものを
時相論理と言います。同じ TL でもこっちの TL は Temporal Logic でなくて Tree Logic、
木です。計算木という木構造を使っていろいろ理論が構築されています。そういうもので
す。それがどんなものかというのは、時相論理については、今日は第1回目だとして第4
回目に話す予定なのですけれども、その時までブラックボックスでいても何となく分から
ないと思うので、こんなものですよという例を1つだけお見せします。
これは CTL という言語で作られた時相論理式です。これが1つの論理式なのです。です
からこれが真だとか偽だとかという1つの命題を表しています。それはもっと細かく見る
と、原始命題、これ以上分解できない命題があって、それに「ならば」とか「任意の」と
か何とか、そういういろいろな記号を使って、複合された1つの命題になっています。こ
れの日本語の解釈は、いつの時点でもこうなっていますと。その Req、これはリクエスト
信号という意味です。Req とか Ack はユーザーが自由に名前を付けられる命題なので、別
に Req でなくても良いのですけれど、私が付けた名前です。ある何らかの要求をするとい
うリクエストです。そのリクエストが真になると、いつか必ず Ack、Ack というのはアク
ノリッジ、分かりました、リクエストする時にあっちが分かったという風にちゃんと分か
ってくれたとか、データをちゃんと受け取ったとかそういうようなものです。それが真に
なるという意味です。直感的に言うとメールを送ったら向こうに必ず届くとか、そんなよ
うなことと似ています。いつの時点でもというのはいつメールを送ってもという意味です。
正月だったら動かないとかそういうことではなくて、いつの時点でもリクエストを送ると、
いつか必ず Ack が向こうに届くということです。それでそれを見ると、今日はあまり詳し
く説明できないのですけど、いつの時点でもというのは AG という記号なのです。All
Globally とかそういうような記号で、AG で1つの記号なのです。Req というのは何も入っ
ていなければこれが真ならばと見做すので、矢印は~ならば~という普通の論理記号です。
いつの時点でもリクエストがその時真であるならば、AF というのはいつか必ずこういうこ
とが起こるという意味です。All Future、Future というのは未来という意味です。或いは
Finally、いつか必ずとか最終的にはとかそういう言葉から来ているのですけれども、いつ
かの時点で必ず Ack が真になりますということを書いています。ですからここはちょっと
勉強しないと書けないので、ユーザーから見れば難しさがあるのです。でも頑張って勉強
してこういうことが書けたとします。そうすると検証ができるということになります。
(21)(3) 検証
モデル検査機、モデルチェッカーというソフトウェアがいろいろ公開されていますので、
それで自動的に検証が行われます。2つのケースに分かれるのですけど、今書いた性質が
成り立つ場合、その場合結果は呆気ないです。その通り検証が終わりましたと、あなたの
言っていた性質は確かに成り立ちますというだけの話です。そういう返事が返ってきます。
性質が成り立たない場合は、反例、エラートレースというものが出力されます。これが何
なのかというと、あなたはこういう性質が成り立つと、例えば決してこんなことは起きま
せんとかと書いてあるのだけれども、いやそうではないです、反例がありますと、つまり
このプロセスがこう実行してその時プロセスBがこう動き出して、その次のこういう微妙
なタイミングでプロセスCがこう動いた時は、これはそうはならないではないですかとい
う反例を具体的に出していくのです。それを分析すると、ああそうだ、そういう時を考え
忘れていたとかというのでデバックする。という風になります。
(22)モデル検査の実施手順(まとめ)
これを纏めるとこういうことです。モデルチェッカーというソフトウェアがあります。
これのアルゴリズムは、私達はユーザーとしては知らなくて良いです。入力が2つありま
す。まずモデルです。これは自分の設計したソフトウェアはこういうものだというのを、
プログラミングでコーディングする直前のモデルレベルのもの、理論的には状態遷移系に
相当するものです。そしてこういうソフトウェアをもし作ったら、こういう性質が成り立
つ筈だというさっきの安全性とか活性を、時相論理のようなもので記述した、或いは時相
論理でなくても良いのですけど、そういう性質を記述して入力します。それでモデルチェ
ッカーは結構難しいアルゴリズムを使って一生懸命これとこれを突き合わせて、検査結果
としてその通りですという時は OK、そうではない場合は反例を出力します。という風にな
ります。
で、こっちのモデルを記述するためにはさっき紹介したように、C言語風のものがあっ
たり、プロセス代数、ちょっと数学的に見える言語もあります。性質を記述するには時相
論理というのが基本ですけど、別にこれでないといけないということはなくて、もしかし
たら将来違うものが出るかもしれないです。あまり普通の人は知らないのですから、実際
これがちょっとネックなのです。こっちはC言語を知っていれば割と取っつきやすいです
から割と良いのです。これはちょっと取っつきにくいです。
(23)他の検証法: Why
では何故モデル検査を使うのかと言うのです。他の方法でそういうことはできないのか
ということです。
まず普通に簡単にできるのはシミュレーションとかテストで、これを否定する訳ではな
いのですけども、実際にソフトウェアを作ってシミュレーションしたりテストしたりする
のですけども、プロセスが複数個動いています。そういうものは全てのインタラクション、
どういうタイミングでどういう風にメッセージ交換するかとか、それから潜在的にこうい
うエラーがないことは確認しているけれど見落としているエラーとか、こういうことまで
考えてなかったとか、そういうことを網羅的に検査するのは不可能です。自分の想定範囲
内で大体良さそうだということができるのが、シミュレーションというテストです。
これで完璧にはできない。でも重要な技術なのは確かなのです。ですからシミュレーシ
ョンとかテストとかは一生懸命やればまず良いのです。それで9割方確実に動くというこ
とはまず分かると思うのです。98%くらい正しいというのは、一生懸命シミュレーション
とテストすれば分かるのです。残りの2%が問題で、このソフトを本当に、例えばロケッ
トに積み込んで人を乗せて木星に飛ばして良いのかと言った時に、いや2%の確率でこの
ソフトには誤りがあります、その時には死ぬかもしれませんでは駄目なのです。だからそ
の場合にはさらに、もっとすごい検証法が必要になります。
すごい検証法の1つとして知られているのが定理証明というものです。数学の定理を証
明するということを理論的な背景としたのです。そういうものを研究者が研究しているの
ですけど、これはやはり難しいということで、専門的知識がかなり必要になったりします。
この定理証明を人間がやっていられませんので機械的にやるのです。機械的に定理を証明
するというのは、人工知能の分野で昔から研究されていますけど、やっぱり複雑な定理の
場合は多大な時間を要するということです。そもそも計算可能性、そもそも定理が証明で
きるのか、原理的にできないのではないかとか、そういう理論的な問題もありますので、
これは今急にと言うよりも将来的な方向としてこういうことがあるのですけども、急にこ
れを手軽に今使えるという段階でもないということです。
ちょうどこれとこれの間がモデル検査なのです。モデル検査というのはこれよりもしっ
かりとちゃんと検査するのだけども、こっち程ではないという辺りで実用的になるかなら
ないかという辺りのところにあるものです。
(24)4.システムとアルゴリズム-モデル検査器の例
実際にどういうシステムがあるか、どういう考え方のアルゴリズムかということです。
まずさっき出てきた SMV というのが有名です。これはカーネギーメロン大学というアメ
リカの大学です。こういうコンピュータ関係でアメリカで3つの大学が先頭走っているの
ですが、そのうちの1つです。後は、普通はスタンフォード大学とそれから MIT、マサチ
ューセッツ工科大学です。これがコンピュータ関係のトップを走っているのです。そのう
ちの1つの大学で作ったものです。これの実績としては、IEEE というアメリカの電気電子
情報関係 の学会というか研究者 や実業家の集まりがあ ります。そこで Futurebus +
standard、私も分からないのですけれども、ハードウェアのバスのすごく高度な規格を作
ったのです。それでこういう規格でやりましょうというのを公表して、スタンダードな規
格を作ったのですけど、それにバグがあるということをこのシステムが発見したというこ
とです。こういうこれをもし作るとこういう悪いことが起こるとかというのを発見したと
いうことです。最近はそれをさらに再実装した NuSMV というシステムが提供されていま
す。
SPIN というのはベル研究所です。アメリカの西海岸にあります。電話を作ったグラハ
ム・ベルが最初に建てたところです。今でもそういう電話関係の研究もやっているけど、
ソフトウェアの研究もやっています。UNIX を作ったところです。UNIX を作った研究者が
ベル研の人です。ここの SPIN というソフトは ACM という、これもやはりコンピュータ関
係のトップレベルのアメリカの学会なのですけれども、そこで Software System Award と
いう賞を受賞しています。優れたソフトウェアに対する賞です。ちなみに Linux のその源
流にある UNIX というソフトもこの賞を受賞しています。それ以外に TCL/TK という普通
のソフトウェアの人が聞いたらすぐ分かるようなソフトウェア、こういうものもどんどん
受賞しているのです。
それからこの UPPAL というのは、リアルタイムシステムを検証するものです。
他にもいろいろあるのですけども、Bogor というのは今度は Java で書かれていて、一般
ユーザーがそれを再利用可能になっている。オブジェクト指向でできているので、再利用
しやすいように作られているものとか、これはプロセス代数に基づく言語で、アニメーシ
ョン記号があるとかです。それから Java PathFinder、JPF というのは NASA です。航空
宇宙局、ロケット、スペースシャトルを飛ばしている NASA です。そこで開発しているも
のです。これは Java でプログラムをそのままコーディングしてしまえという訳です。他の
ものはそのままでは動かないです。プログラミング言語そのものではないのですけども、
Java で普通にプログラムを書くとバイトコードレベルでちゃんと検査するというものです。
(25)モデル検査アルゴリズムの原理
その基本原理なのですけども、基本原理は簡単で、全ての計算経路、さっき言ったよう
に2つのプロセスが動くのでこう行く場合もあるしこう行く場合もあると、いろいろなイ
ンタラクションがあります。それをありとあらゆる場合、全て網羅的に検査するというの
が基本概念です。漏れなく抜けがないのです。だから見落としていたということがないよ
うに、全部の場合を検査するのです。ですので、物凄い計算になるのです。
それで状態遷移図というのはグラフになります。ノードと線のグラフになるので、グラ
フアルゴリズムが中心になってきて、変なところがないかどうかグラフの中を探索するの
で、グラフの探索アルゴリズムとか、そういうことがベースになって網羅的にやるのが基
本姿勢です。
(26)状態爆発の軽減の工夫
ただまともに網羅的にやるとすごい時間が掛かるので、いろいろ工夫はされていて、二
分決定木、BDD というのがコンピュータサイエンス専攻の湊先生とかが研究していますけ
ど、そういうような論理学上のテクニックを使うとか、いろいろ工夫はもちろんしていま
す。それから半順序簡約という、順序を変えてもこれは影響を与えないとか、そういうこ
とを自動的にチェックするとか、それから本来無限なのだけど有限にしないといけないの
で無理やり有限にして、充足可能性判定器、SAT solver というのですけども、命題論理と
かそういうような、或いはブール代数とかそういうことを判定するソフトウェアを使って
実装するとかです。
(27)状態爆発の軽減のその他の工夫
実装レベルでいろいろ、他にもいろいろ言葉だけ挙げていますけども、いろいろなテク
ニックを総合して、実際的には網羅的にやるのだけれども、それを効率よくうまく使って
いるということです。
(28)演習問題
後これは演習問題ということです。
以上で終わります。