セマフォ

出典しゅってん: フリー百科ひゃっか事典じてん『ウィキペディア(Wikipedia)』
語源ごげん腕木うできしき信号しんごう

セマフォえい: semaphore)とは、計算けいさん科学かがくにおいて、並行へいこうプログラミング環境かんきょうでの複数ふくすう実行じっこう単位たんいおもプロセス)が共有きょうゆうする資源しげんにアクセスするのを制御せいぎょするさいの、単純たんじゅんだが便利べんり抽象ちゅうしょう提供ていきょうする変数へんすうまたは抽象ちゅうしょうデータがたである。

概要がいよう[編集へんしゅう]

セマフォは、ある資源しげんなん使用しよう可能かのうかをしめ記録きろくかんがえればわかりやすく、それにその資源しげん使用しようするさい解放かいほうするさいにその記録きろくを「安全あんぜんに」(すなわち競合きょうごう状態じょうたいとなることなく)え、必要ひつようおうじて資源しげん使用しよう可能かのうになるまで操作そうさむすびついている。セマフォは競合きょうごう状態じょうたいふせ便利べんりなツールであるが、セマフォを使つかうことでプログラムにおける競合きょうごう状態じょうたいがなくなると保証ほしょうするものではない。任意にんい資源しげんあつかうセマフォをカウンティングセマフォが0と1に制限せいげんされている(ロック/アンロック、使用しよう可能かのう/使用しよう不可ふか意味いみがある)セマフォをバイナリセマフォぶ。後者こうしゃミューテックス同等どうとう機能きのうつ。

セマフォの概念がいねんはオランダじん計算けいさん科学かがくものエドガー・ダイクストラ考案こうあんした[1]いまではさまざまなオペレーティングシステム採用さいようされている。

en:semaphore」の本来ほんらい語義ごぎは「視覚しかくによる通信つうしん信号しんごう全般ぜんぱんし、腕木うでき通信つうしんや、それから派生はせいした鉄道てつどう腕木うでき信号しんごう(や自動車じどうしゃ方向ほうこう指示しじ)、手旗てばた信号しんごうなどがふくまれる。

図書としょしつのたとえ[編集へんしゅう]

ある図書としょしつ学習がくしゅうしつが10部屋へやあり、それぞれの学習がくしゅうしついち1人ひとり学生がくせい使用しようするとする。争奪そうだつせんはじまらないよう、学生がくせい受付うけつけカウンターで学習がくしゅうしつ使用しようもうむことになっている。学習がくしゅうしつ使用しようえたら、学生がくせい受付うけつけしょってその学習がくしゅうしついたことをらせなければならない。すべての学習がくしゅうしつまっている場合ばあい学生がくせい受付うけつけしょ学習がくしゅうしつくのをつ。

受付うけつけカウンターの図書としょがかりはどの学習がくしゅうしついているかは把握はあくしておらず、たんいている部屋へやすうのみをっている。学生がくせいもうんできたとき、図書としょがかり部屋へやすうから1をく。学生がくせい学習がくしゅうしつ利用りようえたとき、図書としょがかり部屋へやすうに1をくわえる。学習がくしゅうしつ使用しよう許可きょかあたえられたとき、その部屋へや必要ひつようなだけ使つかつづけることができる。学習がくしゅうしつ事前じぜん予約よやくすることはできない。

このシナリオでは、受付うけつけカウンターがセマフォ、学習がくしゅうしつ資源しげん学生がくせい実行じっこう単位たんい相当そうとうする。また、セマフォの初期しょきは10になっている。学生がくせい学習がくしゅうしつ使用しようもうんで許可きょかされたとき、セマフォから1がかれて9になる。つぎ学生がくせいのときには8、さらにつぎは7となる。1をくとセマフォまけになるという状態じょうたい学生がくせいもうんだ場合ばあい、その学生がくせいたされる[2]複数ふくすうじん学生がくせいっているとき、かれらは行列ぎょうれつ形成けいせいするか、いずれかの学生がくせい学習がくしゅうしつ使用しようえて受付うけつけカウンターにやってきたときにいた部屋へやてる。方式ほうしきには、ラウンドロビン・スケジューリング方式ほうしきとうがある(セマフォがただしく制御せいぎょされるよう実装じっそうされていれば、方式ほうしき妥当だとうなものであればよい)。

重要じゅうよう観点かんてん[編集へんしゅう]

複数ふくすう資源しげんたいして使用しようする場合ばあい、セマフォは個々ここ資源しげん使用しよう/解放かいほう状態じょうたい把握はあくせず、たん個数こすうのみを保持ほじする。特定とくてい資源しげん指定していしたい場合ばあいは、機構きこう必要ひつようとされる(複数ふくすうのセマフォの組合くみあわせでも可能かのう)。

実行じっこう単位たんいぐんはそのプロトコルにしたがうというてん信頼しんらいされている。1つの実行じっこう単位たんい間違まちがった動作どうさをすれば、公平こうへいせい安全あんぜんせいそこなわれ、性能せいのう低下ていか不正ふせい動作どうさフリーズクラッシュなどが発生はっせいしうる。たとえば、つぎのような動作どうさ間違まちがった動作どうさである。

  • 資源しげん要求ようきゅうしておいて、使用しよう解放かいほうわすれる。
  • 要求ようきゅうしたことのない資源しげん解放かいほうする。
  • 使つかっていない資源しげん長期ちょうきわたって獲得かくとくしたままにする。
  • 要求ようきゅうせずに資源しげん使用しようする。
  • 解放かいほうみの資源しげんであるにもかかわらず当該とうがい資源しげん継続けいぞく使用しようする。

ぜん実行じっこう単位たんいがその規則きそくしたがったとしても、資源しげん複数ふくすう種類しゅるいあって、それぞれにセマフォが設定せっていされている場合ばあい実行じっこう単位たんい複数ふくすう資源しげん同時どうじ使用しようするならあらたな問題もんだい発生はっせいしうる。たとえば、食事しょくじする哲学てつがくしゃ問題もんだいがそのような状況じょうきょうしめしている。

意味いみろん実装じっそう[編集へんしゅう]

セマフォ変数へんすう重要じゅうよう属性ぞくせいとして、その変更へんこうには特定とくてい関数かんすうぐん使つかわなければならないというてんげられる。ここではそれらの関数かんすうを wait() と signal() とする。

カウンティングセマフォでの2つの操作そうさは、歴史れきしてきには V(または signal())と P(または wait())と記述きじゅつされる。V操作そうさはセマフォSインクリメントし、P操作そうさデクリメントする。かく括弧かっこかこまれた部分ぶぶん不可分ふかぶん操作そうさであることを意味いみし、その部分ぶぶん途中とちゅう経過けいか実行じっこう単位たんいからはえない。

セマフォSは、その時点じてん使用しよう可能かのう資源しげん個数こすうである。P操作そうさ資源しげん獲得かくとくしようとするもので、セマフォでまもられている資源しげん使用しよう可能かのうになるまでビジーウェイトまたはスリープ英語えいごばんつことになる。V操作そうさはそのぎゃくであり、使用しようしていた資源しげん解放かいほうする。

wait() と signal() を簡単かんたん説明せつめいするとつぎのようになる。

  • wait(): セマフォのを1だけデクリメントする。その結果けっかまけになるなら wait() を実行じっこうしている実行じっこう単位たんいはブロックされる。つまり、セマフォのちキューに追加ついかされる。
  • signal(): セマフォのを1だけインクリメントする。その、インクリメントまえまけだったら(つまり資源しげん状態じょうたい実行じっこう単位たんいがあるなら)、セマフォのちキューじょうにあるブロックされた実行じっこう単位たんいをレディ(実行じっこう可能かのう)キューにうつす。

おおくのOSは効率こうりつてきなセマフォのプリミティブを提供ていきょうしており、セマフォをインクリメントしたさいには1つだけ状態じょうたい実行じっこう単位たんいをアンブロックする。すなわち、複数ふくすう実行じっこう単位たんい同時どうじにアンブロックしたさい無用むようなセマフォのチェック処理しょりふせいでいる。

カウンティングセマフォの概念がいねんは、いち複数個ふくすうこ資源しげん獲得かくとく解放かいほうできるように拡張かくちょうでき、UNIXでの実装じっそうもそのようになっている。その場合ばあいVおよびP操作そうさつぎのように修正しゅうせいされる。

function V(semaphore S, integer I):
    [S ← S + I]

function P(semaphore S, integer I):
    repeat:
        [if S >= I:
            S ← S - I
            break]

リソーススタベーションふせぐため、セマフォには実行じっこう単位たんいキュー通常つうじょうFIFO)が1つ付属ふぞくしている。セマフォがゼロのときにP操作そうさをすると、その実行じっこう単位たんいはセマフォ付属ふぞくのキューに追加ついかされる。べつ実行じっこう単位たんいV操作そうさでセマフォをインクリメントしたとき、キューじょう実行じっこう単位たんいがあれば、そのうちの1つをキューからはずして実行じっこう再開さいかいさせる。実行じっこう単位たんい優先ゆうせん設定せっていされている場合ばあい、キューじょう優先ゆうせんじゅん実行じっこう単位たんいならべるなどして、もっと優先ゆうせんたか実行じっこう単位たんい最初さいしょ実行じっこう再開さいかいできるようにする。

実装じっそうにおいてインクリメント/デクリメントや比較ひかく不可分ふかぶんせい保証ほしょうされていない場合ばあい、インクリメントやデクリメントがおこなわれなかったり、セマフォ不正ふせいになる危険きけんせいしょうじる。不可分ふかぶんせい達成たっせいするには、リード・モディファイ・ライト英語えいごばんって、変更へんこうくわえて、むという処理しょりサイクル)を不可分ふかぶん実行じっこうできる機械きかい命令めいれい使用しようする。そのような機械きかい命令めいれいがない場合ばあいデッカーのアルゴリズムなどのソフトウェアによる排他はいた制御せいぎょ使用しようする。シングルプロセッサのシステムでの不可分ふかぶん操作そうさは、プリエンプション一時いちじてき禁止きんししたり、をマスクしたりすることでも実現じつげんできる。マルチプロセッサシステムではそれだけでは不十分ふじゅうぶんで、おなじセマフォを共有きょうゆうする2つのプログラムが別々べつべつのプロセッサじょう同時どうじ動作どうさしている場合ばあい対処たいしょできない。そのためテスト・アンド・セット命令めいれいなどを使用しようしてセマフォ変数へんすうへのアクセスをロックする必要ひつようがある。

れい: 生産せいさんしゃ/消費しょうひしゃ問題もんだい[編集へんしゅう]

生産せいさんしゃ/消費しょうひしゃ問題もんだい英語えいごばんでは、1つの実行じっこう単位たんい生産せいさんしゃ)がデータを生成せいせいし、もう1つの実行じっこう単位たんい消費しょうひしゃ)がそれらをって使用しようする。データのわたしは最大さいだいサイズNのキューでおこない、つぎのような条件じょうけんしたがう。

  • キューがそら場合ばあい消費しょうひしゃ生産せいさんしゃがデータを生成せいせいするのをたなければならない。
  • キューが満杯まんぱい場合ばあい生産せいさんしゃ消費しょうひしゃがデータを消費しょうひするのをたなければならない。

生産せいさんしゃ/消費しょうひしゃ問題もんだいをセマフォで解決かいけつする場合ばあい、キューの状態じょうたいを2つのセマフォであらわす。emptyCount はキューじょういているスロットすう保持ほじし、fullCount はキューじょう要素ようそすう保持ほじする。完全かんぜんせい維持いじするには、emptyCount実際じっさいきスロットすうよりちいさくなるようにし、fullCount実際じっさいのキューじょう要素ようそすうよりちいさくなるようにする(どちらも実際じっさいかずえてはならない)。きスロットと要素ようそは、そらはこたされたはこという2種類しゅるい資源しげんあらわしており、セマフォ emptyCountfullCount はそれら資源しげんについての制御せいぎょ管理かんりする。

バイナリセマフォ useQueue は、たとえば2つの生産せいさんしゃ同時どうじにデータをキューに格納かくのうしようとするなどといった不正ふせい状態じょうたい発生はっせいしないことを保証ほしょうするためにある。このバイナリセマフォはミューテックス代替だいたいすることもできる。

emptyCount初期しょきは N、fullCount初期しょきは0、useQueue初期しょきは1である。生産せいさんしゃつぎのような処理しょりかえす。

produce:
    P(emptyCount)
    P(useQueue)
    putItemIntoQueue(item)
    V(useQueue)
    V(fullCount)

消費しょうひしゃつぎのような処理しょりかえす。

consume:
    P(fullCount)
    P(useQueue)
    item ← getItemFromQueue()
    V(useQueue)
    V(emptyCount)

具体ぐたいてきにはつぎのような動作どうさをする。

  1. 1つの消費しょうひしゃクリティカルセクションはいる。fullCount は0なので、消費しょうひしゃはブロックする。
  2. いくつかの生産せいさんしゃ生産せいさんしゃがわのクリティカルセクションにはいる。emptyCount制限せいげんされるのでN以上いじょう生産せいさんしゃはクリティカルセクションにれない。
  3. 生産せいさんしゃuseQueue によりいちに1つずつキューにアクセスし、データをキューにれていく。
  4. 最初さいしょ生産せいさんしゃがクリティカルセクションをけるとき、fullCount がインクリメントされるので、ブロックしていた消費しょうひしゃがクリティカルセクションない処理しょりすすむことができる。

emptyCount はキューじょう実際じっさいきスロットすうよりちいさくなる可能かのうせいがある。たとえば、複数ふくすう生産せいさんしゃがデクリメントをおこなっても、useQueue によってキューへのデータ投入とうにゅう逐次ちくじされるためである。したがってつねemptyCount + fullCount ≤ N であり、等号とうごうつのは生産せいさんしゃ消費しょうひしゃまったくクリティカルセクションにはいっていない場合ばあいだけである。

関数かんすうめい語源ごげん[編集へんしゅう]

歴史れきしてきもちいられてきた名前なまえであるPVは、オランダ単語たんご頭文字かしらもじ由来ゆらいしている。Vverhogen増加ぞうかする)を意味いみする。Pについては、proberen(テストする)[3]passeer通過つうか)、probeerこころみる)、pakken(つかむ)などいくつかの説明せつめいがある。セマフォの本来ほんらい意味いみである腕木うでき通信つうしんから、Vverhoog腕木うできげる、通行つうこう禁止きんし)、Ppasseren腕木うできげる、通行つうこう許可きょか)とするせつもある。ただしダイクストラ自身じしんPprobeer te verlagenらすことをこころみる)をりゃくしたかばん prolaag頭文字かしらもじだとしている[4][5][6][7]。この混乱こんらんのもとは、オランダincreasedecrease相当そうとうするかたりがどちらも Vはじまるためで、かといってオランダ単語たんごをそのまま使つかってもオランダらないひとはかえって混乱こんらんするとダイクストラがかんがえたためである。

ALGOL 68Linuxカーネル[8]、いくつかの英語えいご教科書きょうかしょでは、PVはそれぞれ downup とされている。ソフトウェア工学こうがくでは一般いっぱんwaitsignalacquirerelease[注釈ちゅうしゃく 1]pendpost などとばれることがおおい。教科書きょうかしょによってはもともとのオランダ頭文字かしらもじ一致いっちするよう procurevacate としているものもある。

セマフォとミューテックス[編集へんしゅう]

ミューテックス基本きほんてきにバイナリセマフォと等価とうかであり、ときには基本きほん実装じっそう同一どういつということもある。ただし、ミューテックスは2つの実行じっこう単位たんい同時どうじ共用きょうよう資源しげんにアクセスするのを防止ぼうしする構成こうせいぶつあらわし、バイナリセマフォは単一たんいつ資源しげんへのアクセスを制限せいげんする構成こうせいぶつあらわす。

おおくの場合ばあい、ミューテックスには「所有しょゆうしゃ」の概念がいねんがある。すなわちミューテックスをロックした実行じっこう単位たんいだけがそれをアンロックすることができる。対照たいしょうてきにセマフォにはそのような制限せいげんがなく、上述じょうじゅつ生産せいさんしゃ/消費しょうひしゃ問題もんだいれいでもそれを利用りようしている。

したがって基本きほんてきには、ミューテックスは実行じっこう単位たんいなどの実行じっこう実体じったいむすびついており、セマフォは資源しげんむすびついている。

環境かんきょうごとの使用しよう方法ほうほう[編集へんしゅう]

POSIX[編集へんしゅう]

POSIX準拠じゅんきょ環境かんきょうでは、semaphore.h宣言せんげんされたかた関数かんすう使用しようできる。sem_init()無名むめいのセマフォを生成せいせいする[9]か、sem_open()名前なまえきセマフォを生成せいせいまたはオープンできる[10]sem_init()引数ひきすうpsharedゼロの指定していすることで、プロセスあいだ共有きょうゆうされるセマフォを生成せいせいすることもできる。sem_wait()でセマフォのらし(ロック)、sem_post()でセマフォのやす(ロック解除かいじょ)。sem_destroy()無名むめいのセマフォを破棄はきする。sem_close()名前なまえきセマフォをクローズする。

Windows[編集へんしゅう]

WindowsWin32 APIでは、CreateSemaphore()関数かんすうでセマフォを生成せいせいまたはオープンできる。WaitForSingleObject()関数かんすうでセマフォを待機たいきする(カウント減少げんしょう)。ReleaseSemaphore()関数かんすうでセマフォを解放かいほうする(カウント増加ぞうか)。CloseHandle()関数かんすうでセマフォのハンドルをクローズする(オブジェクト破棄はき[11]OpenSemaphore()関数かんすう既存きそん名前なまえきセマフォをオープンできる[12]。スレッドあいだ同期どうきだけでなく、プロセスあいだ同期どうき使用しようすることもできる[13][14]

MFCにはC++コンストラクタ/デストラクタによるRAII機構きこう利用りようした、Win32同期どうきオブジェクトのラッパークラスCSemaphore[15]用意よういされている(実際じっさいにはCSingleLockわせて使用しようすることがおお[16])。

.NET[編集へんしゅう]

.NET Framework 2.0以降いこうでは、System.Threading.Semaphore クラスを使つかう。バージョン1.1以前いぜんでは自作じさくするかWin32 APIを必要ひつようがある。ローカルセマフォはスレッドあいだ同期どうきにのみ使用しようできるが、名前なまえきシステムセマフォはプロセスあいだ同期どうき使用しようすることもできる[17]Semaphoreクラスは.NET Coreおよび.NET 5以降いこうでも利用りよう可能かのうだが、Windows以外いがいのプラットフォームではスレッドあいだ同期どうきにのみ使用しようでき、プロセスあいだ同期どうきには使用しようできない[18]

.NET Framework 4.0以降いこうでは、どういちプロセスないのスレッドあいだ同期どうきであれば、軽量けいりょうされたSystem.Threading.SemaphoreSlim クラスを利用りようできる[19]

Java[編集へんしゅう]

Javaでは、java.util.concurrent.Semaphore クラスを使つかう。Java 5 以降いこう使用しよう可能かのうである。

Perl[編集へんしゅう]

Perlでは、Thread::Semaphore モジュールや、あたらしくはCoro::Semaphore モジュールなどを使つかう。

Python[編集へんしゅう]

Pythonでは、threadingモジュールちゅうSemaphoreクラスが用意よういされている。

Swift[編集へんしゅう]

Swiftでは、Grand Central Dispatch英語えいごばん機能きのうとして Dispatch フレームワークちゅうDispatchSemaphore クラスが用意よういされている。

脚注きゃくちゅう[編集へんしゅう]

注釈ちゅうしゃく[編集へんしゅう]

  1. ^ Javajava.util.concurrent.Semaphoreクラスなどで使用しようされている。

出典しゅってん[編集へんしゅう]

  1. ^ Dijkstra, Edsger W. Cooperating sequential processes (EWD-123). E.W. Dijkstra Archive. Center for American History, University of Texas at Austin. (original; transcription) (September 1965)
  2. ^ The Little Book of Semaphores Allen B. Downey
  3. ^ Silberschatz, Galvin & Gagne 2008, p. 234
  4. ^ Dijkstra, Edsger W. Over Seinpalen (EWD-74). E.W. Dijkstra Archive. Center for American History, University of Texas at Austin. (original; transcription)
  5. ^ Dijkstra, Edsger W. MULTIPROGAMMERING EN DE X8 (EWD-51). E.W. Dijkstra Archive. Center for American History, University of Texas at Austin. (original; transcription) (オランダ)
  6. ^ ダイクストラ自身じしん英語えいごやくさいして "try-and-decrease" としているが、口語体こうごたいの "try-and..."まぎらわしい。
  7. ^ (PATCH 1/19) MUTEX: Introduce simple mutex implementation Linux Kernel Mailing List, 19 December 2005
  8. ^ Linus Kernel hacking HOWTO LinuxGrill.com
  9. ^ sem_init | The Open Group Base Specifications Issue 7, 2018 edition IEEE Std 1003.1-2017
  10. ^ sem_open | The Open Group Base Specifications Issue 7, 2018 edition IEEE Std 1003.1-2017
  11. ^ Using Semaphore Objects - Win32 apps | Microsoft Learn
  12. ^ OpenSemaphoreW function (synchapi.h) - Win32 apps | Microsoft Learn
  13. ^ CreateSemaphoreA function (winbase.h) - Win32 apps | Microsoft Learn
  14. ^ CreateSemaphoreW function (synchapi.h) - Win32 apps | Microsoft Learn
  15. ^ CSemaphore Class | Microsoft Learn
  16. ^ Multithreading: How to Use the MFC Synchronization Classes | Microsoft Learn
  17. ^ Semaphore Class (System.Threading) | Microsoft Learn
  18. ^ 同期どうきプリミティブの概要がいよう - .NET | Microsoft Learn
  19. ^ Semaphore と SemaphoreSlim - .NET | Microsoft Learn

参考さんこう文献ぶんけん[編集へんしゅう]

  • Silberschatz, Abraham; Galvin, Peter Baer; Gagne, Greg (2008), Operating System Concepts (8th ed.), John Wiley & Sons. Inc, ISBN 978-0-470-12872-5 

関連かんれん項目こうもく[編集へんしゅう]

外部がいぶリンク[編集へんしゅう]