#pragma twice

KAB-studio > プログラミング > #pragma twice > 273 Version 14.06 ミューテックスで排他処理

#pragma twice 273 Version 14.06 ミューテックスで排他処理

前のページへ 表紙・目次へ 次のページへ

 Version 14.06
ミューテックスで排他処理

今回は、前回作ったミューテックスのプログラムを実際に動かして、排他
処理がどのように行われるのか確認してみます
おー
まず、前回作ったのと同様のプログラムをあともうふたつ作ってくださ

……へ? ボタン作ってイベントハンドラ作って、ってのをあと2回?
そう。プロジェクト名は ProcessB と ProcessC 。もちろん、各ボタンを
押したら前回の5つの関数が呼ばれるようにしてください
はい、できたよ……
まぁ、本当はワークスペースのフォルダまるごと複製しても良かったんだ
けど
!!
でもプロジェクト名とかも変えた方がわかりやすいから、ね?
ううう……
それと、前回のも含めて、 ProcessA ProcessB ProcessC の3つの
プロジェクトを、それぞれ別の VC++ で開いてください
え!?  VC って一度に3つもあげられるの?
うん、 VC そのものは SDI だから
そういえばそんな複雑な話あったね……でもなんでわざわざ VC を?
こうすれば、それぞれ独立してデバッグ実行できるから
あー
そうすればわかりやすいからね。さて、前回紹介したプログラムには、次
の5つの関数があります

Create()    // ミューテックスを作成します。
Open()      // ミューテックスを取得します。
Wait()      // ミューテックスを監視して待機状態に入ります。
Release()   // ミューテックスを手放します。
Close()     // ミューテックスを削除します。

これを各ボタンで呼ぶようにしたんだよね
そう、だから今はそれぞれいつでも呼べる状態になっているはず。そこで
まずミューテックスを作ってみます。 ProcessA を実行して、 Create() を
呼びます

ProcessA::Create()

ほい
成功すれば、アウトプットウィンドウにハンドルが出力されます
出たよ
これで "ProcessesMutex" という名前のミューテックスが作られました
おぉ
終了する時には、 Close() を呼んでミューテックスを削除してくださ

忘れたら?
別に問題ないかも……同じ名前のミューテックスなら何度作ってもひとつ
だけだし
あ、そっか
さて、前回説明したように、現在のコードでは Create() を呼ぶとその場
で取得します。つまり、現在は ProcessA がこのミューテックスを持ってい
るわけです
 ProcessA が持ってる、と
次に、 ProcessB を実行してください
ほい実行
この時点では ProcessB は ProcessA が作ったミューテックスを持ってい
ないので、ここで開きます。 ProcessB の Open() を呼び出してください

ProcessB::Open()

ほい。あ、ハンドル出た。あ! ProcessA のと同じ!
あ、これはたまたま
へ?
同期オブジェクトのハンドルはプロセス毎に違うから。ウィンドウハンド
ルみたいなグローバルなものじゃないんだよね
む……喜んで損した
でもそういう視点を持つことは重要だよ
フォローありがとー
う……。で、ここで ProcessB は ProcessA が作ったミューテックスを開
いたわけだけど、この段階では所有権はありません
 ProcessA が持ってるから?
そういうこと。それを確認するため、 ProcessB で Wait() を呼び出して
ください

ProcessB::Wait()

ほい。あ、待ち続けてる……
 ProcessB は ProcessA が作ったミューテックスの監視を始めました。と
いうことは、監視が終わるのは?
 ProcessA が手放したとき!
というわけで、 ProcessA の Release() を呼び出してください

ProcessA::Release()

ほい。あ、 ProcessB で【待機終了】って出た!
というわけで、 ProcessA がミューテックスを解放すれば、 ProcessB の
監視状態が解かれるわけです。図にすると……

ProcessA                              ProcessB
Create() でミューテックス           
"ProcessesMutex" の作成及び所有。   
                                      Open() でミューテックスを取得。
                                      "ProcessesMutex" と同じもの。
                                      Wait() で "ProcessesMutex" を
"ProcessesMutex" 所有中 ←←←←←←←監視開始。
"ProcessesMutex" 所有中               (監視中)
Release() で解放→→→→→→→→→→→監視終了。
"ProcessesMutex" の所有権喪失。       "ProcessesMutex" を所有。

んー、よーするに "ProcessesMutex" はひとつだけ、ってことねー
そういうこと。それがミューテックスの一番の特徴かな。ミューテックス
っていう〈バトン〉は、名前ごとにひとつだけ
 ProcessA が持ってるあいだは ProcessB は待ち続ける、 ProcessA が手
放したら今度は ProcessB にそのバトンが渡される
 ProcessB に渡された証拠に、この状態で ProcessA の Wait() を呼ぶ

お、【待機開始】した
で、 ProcessB の Release() を呼ぶと
【待機終了】! なるほどねー、 ProcessA と ProcessB でバトンを交換
しあってるわけね
では、今度は〈みっつのプロセスでバトンを待つ〉というのをしてみま
す。一度全部閉じてから、みっつの VC で ProcessA ProcessB ProcessC を
実行して
ほいほいほい
次に

ProcessA::Create()
ProcessB::Open()
ProcessC::Open()
ProcessB::Wait()
ProcessC::Wait()

とします
ミューテックスを持ってんのは ProcessA で、それを ProcessB と 
ProcessC が待つわけね。お、両方とも待ち始めたよ
この状態で

ProcessA::Release()

と、 ProcessA の Release() を呼ぶと
ミューテックス、解放! ProcessB に【待機終了】って出た……けど、
ProcessC はまだ待ちっぱなし
だって、バトンはひとつだから
あ! そっか、バトンは ProcessB に渡ってるから、 ProcessC はまだ
待ってるんだ……
 ProcessB が ProcessC よりも先に待ち始めたから、 ProcessA が手放し
た時のシグナルは ProcessB にだけ送られます
そうすると ProcessB はシグナルを受け取って待つのをやめる
 ProcessC はシグナルが送られてこないのでまだ待ち続けます。そこで

ProcessB::Release()

と、 ProcessB の Release() を呼ぶと
 ProcessC の【待機終了】って出た! なるほど、 ProcessB が手放すと
バトンが ProcessC に渡されるわけね
そういうこと。図で書くと

ProcessA                ProcessB                ProcessC
Create() 作成                                   
及び所有。                                      
所有中                  Open() で取得。         
所有中                                          Open() で取得。
所有中←←←←←←←←←Wait() で監視開始。
所有中←←←←←←←←←←←←←←←←←←←←←Wait() で監視開始。
所有中                 (監視中)              (監視中)
Release() で解放。→→→監視終了。             (監視中)
                        所有中                 (監視中)
                        Release() で解放。→→→監視終了。

なるほどねー
こういった処理は、たとえばファイルアクセスの排他処理に使用します。
〈所有中〉の間だけファイルアクセスができるようにする、とか
そっか、そうすればファイルにアクセスできるのは1プロセスだけ!
そういうこと。まさに排他制御、ミューテックスらしい使い方というわけ
です
あ、でもこの前ファイルの排他制御やったけど……
ファイルの排他制御だと、終わったことを報せるのが面倒だから
あ、ってゆーか、同期オブジェクトは〈終わったことを報せる〉のが簡単
なんだね
そうだね、 API ひとつで監視することができるから。ただ、実際にはこ
れらを組み合わせるのが一番かな
そういえばそんなこと言ってたね
今回は複数のプロセスを使った例だけど、これをスレッドで実現すると

・ファイルへのアクセスは1プロセスのみ。
・複数の処理をする際には必要な数だけスレッドを作る。
・ファイルへのアクセスはミューテックスを使用して管理する。

こうすれば、ファイルに複数のスレッドから同時に書き込むことはなくな
ります
ミューテックスってバトンを持ったスレッドだけがファイルにアクセスで
きる、ってわけね

/*
    Preview Next Story!
*/
こういうふうにひとつずつ追っていくとわかりやすいね
まぁバトンみたいなものとして作られたからね
そう考えると簡単簡単
でもだからこその問題があるんだよねー
え”
というわけで次回
< Version 14.07 デッドロック! >
につづく!
はまると怖い罠がそこには棲んでいるのです……
んー全然怖くない
はまって4徹
怖!!
 
del.icio.us 登録する
Yahoo!ブックマーク 詳細を表示 users
livedoorクリップ 詳細を表示 livedoorクリップ ブックマーク数
はてなブックマーク 詳細を表示 はてなブックマーク ブックマーク数
RSSに登録
del.icio.us 登録する
Yahoo!ブックマーク 詳細を表示 users
livedoorクリップ 詳細を表示 livedoorクリップ ブックマーク数
はてなブックマーク 詳細を表示 はてなブックマーク ブックマーク数
 
このページは、Visual C++ 6.0を用いた C++ 言語プログラミングの解説を行う#pragma twiceの一コンテンツです。
詳しい説明は#pragma twiceのトップページをご覧ください。