#pragma twice

KAB-studio > プログラミング > #pragma twice > 276 Version 14.09 セマフォで排他処理

#pragma twice 276 Version 14.09 セマフォで排他処理

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

 Version 14.09
セマフォで排他処理

「前回はセマフォを使ったプログラムを紹介しました」
『ミューテックスと違ってバトンはふたつ、ってことだったね』
「というわけで、今回は実際にそれを試してみます。ミューテックスの時、
つまり Version 14.06 ( No.273 ) の時と同じように、 
ProcessA ProcessB ProcessC の3つのプロジェクトを用意して」
『ミューテックスの時のをそのまま使ってもいい?』
「もちろん。同じようにボタンを5つずつ作って」

Create()    // セマフォを作成します。
Open()      // セマフォを取得します。
Wait()      // セマフォを監視して待機状態に入ります。
Release()   // セマフォを手放します。
Close()     // セマフォを削除します。

「を呼ぶようにしてください」
『この辺も同じね』
「さて、では実際に試してみます。前回のプログラムでは」

// セマフォを作成します。
void Create()
{
    g_hSemaphore = CreateSemaphore( NULL, 2, 2, SEMAPHORE_NAME );
    TRACE( "%x\n", g_hSemaphore );
}

「としました。つまり、バトンの数は2、最初の空いている数もその2、と
いうことになります」
『バトンは2本ね』
「今、 ProcessA ProcessB ProcessC の3つのプロセスを使うので、当然ひ
とつ余ります」
『余ると?』
「余ると、バトンが空くのを待つことになります。余らなかったふたつのプ
ロセスは、バトンをもらったらすぐに処理をします」
『ん〜?』
「というわけで実際に試してみましょう。まず」

ProcessA::プロセス実行
ProcessB::プロセス実行
ProcessC::プロセス実行

「と、まぁ普通に3つともデバッグ実行してください」
『はーい』
「次に

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

「と、 ProcessA はセマフォを作成して、残りのふたつはそのセマフォを開
いてください」
『名前が同じだから、同じセマフォを開くんだね』
「そういうこと。これで準備はできました。それでは同期のテストを開始し
ます。まず、現在のバトンの状況はこうなっています」

バトン1:空き
バトン2:空き

『バトン2本とも空いてるわけね』
「次に」

ProcessA::Wait()

「と、 ProcessA はセマフォを監視してください」
『ほい。……あれ? 待たないよ? あっという間に待機終了。しちゃった
よ?』
「それがセマフォ、ってこと。前回説明したでしょ」

○バトンの数が1以上:
 ・バトンをもらって動作開始
 ・バトンの数が1減る
○バトンの数がゼロ:
 ・バトンがないので、バトンが空くまで待ちます。
 ・バトンはゼロのまま

『ああ! バトンは2本ある、そのうちの1本もらって動作開始、動作開始
ってことは待たないってことだから、 WaitForSingleObject() からすぐに
返ってきちゃうんだ!』
「そういうこと。だから、現在の状況は

バトン1:ProcessA 所有中
バトン2:空き
ProcessA::バトン1所有中(よって処理中)
ProcessB::何もしてません
ProcessC::何もしてません

「という状況」
『バトン1が ProcessA に渡って、 ProcessA はそのバトン受け取ってなん
かしてるはず、ってわけね』
「次に」

ProcessB::Wait()

「と、 ProcessB もセマフォを監視してください」
『これもバトン取っちゃうからすぐに返ってくるんだよね。うん、返ってき
た』
「現在の状況はこうなります」

バトン1:ProcessA 所有中
バトン2:ProcessB 所有中
ProcessA::バトン1所有中(よって処理中)
ProcessB::バトン2所有中(よって処理中)
ProcessC::何もしてません

「この状態では、バトンの空きがありません」
『2本とも使われてるわけね』
「イメージとしては、トラック2つの競技場を、選手ふたりがバトンを持っ
て全力疾走してるイメージ」
『全然疾走してないけど』
「さて、この例で行くと ProcessC はもうひとりの走者ということになりま
す。ですが」
『バトンがないから走れない!』
「そういうこと」

ProcessC::Wait()

「として、 ProcessC もセマフォを監視してください」
『ほい。お、今度は返ってこない! ずっと待機開始。のままだ』
「現在の状態はこうです」

バトン1:ProcessA 所有中
バトン2:ProcessB 所有中
ProcessA::バトン1所有中(よって処理中)
ProcessB::バトン2所有中(よって処理中)
ProcessC::バトンが空くのを待っています

「バトンは2本しかありません。が、すでに ProcessA と ProcessB が持っ
ているため、 ProcessC はバトンが空くのを待っています」
『だから WaitForSingleObject() から返ってこないわけね』
「そこで、バトンをひとつ手放します」

ProcessA::Release()

「 ReleaseSemaphore() はセマフォのカウントを減らす、つまりバトンを返
す関数です」
『これを呼ぶと……あ、 ProcessC が待機終了。になった!』
「この瞬間を見てみましょう。まず、 ReleaseSemaphore() が呼ばれたこと
でバトンがひとつ空きます」

バトン1:空き
バトン2:ProcessB 所有中
ProcessA::何もしてません(バトン1を手放したため)
ProcessB::バトン2所有中(よって処理中)
ProcessC::バトンが空くのを待っています

「すると、一番最初に待機していたプロセスに、シグナルがオンになったこ
とが伝えられます」

バトン1:空き→→→→→→→→→→→→→→→→→
バトン2:ProcessB 所有中                      ↓
ProcessA::何もしてません                       ↓
ProcessB::バトン2所有中(よって処理中)       ↓
ProcessC::バトンが空いた!←←←←←←←←←←←

「そこで、 ProcessC はさっそくバトン1を取得します」

バトン1:ProcessC 所有中
バトン2:ProcessB 所有中
ProcessA::何もしてません
ProcessB::バトン2所有中(よって処理中)
ProcessC::バトン1所有中(よって処理中)

「バトンを受け取ったので監視は終了、処理を開始するわけです」
『なるほどねー。つまりさ、バトンをパスしたってことでしょ?』
「そういうこと。 ProcessC っていうランナーは ProcessA と同じコースで
待機していて、 ProcessA からバトンを受け取ったので全力疾走開始。 
ProcessA は代わりに走るのをやめたわけです」
『まさにリレーねー』
「実際のところ、ミューテックスもセマフォも〈バトンリレー〉をするため
の仕組みだから」
『そか、できて当然ってわけね』
「ただ、ミューテックスとセマフォって仕組みとか使い方が違うから」
『確かにこれは混乱するよね……セマフォのデフォルトのカウントとか』
「でもやりたいことは一緒。これをちゃんと理解できてればミューテックス
と同じように普通に使えると思うよ」

/*
    Preview Next Story!
*/
『次回はタイマーね。あれ? でもタイマーって前に使わなかった?』
「タイマーって全部で3つくらいあるから」
『そのうちのひとつ?』
「そゆこと」
「というわけで次回」
< Version 14.10 タイマーを使おう! >
『につづく!』
「ちなみに一番使わないタイマー」
『え”』
 
del.icio.us 登録する
Yahoo!ブックマーク 詳細を表示 users
livedoorクリップ 詳細を表示 livedoorクリップ ブックマーク数
はてなブックマーク 詳細を表示 はてなブックマーク ブックマーク数
RSSに登録
del.icio.us 登録する
Yahoo!ブックマーク 詳細を表示 users
livedoorクリップ 詳細を表示 livedoorクリップ ブックマーク数
はてなブックマーク 詳細を表示 はてなブックマーク ブックマーク数
 
このページは、Visual C++ 6.0を用いた C++ 言語プログラミングの解説を行う#pragma twiceの一コンテンツです。
詳しい説明は#pragma twiceのトップページをご覧ください。