排他制御の仕組1
まず
共有変数への排他制御を 考えてみる
共有変数に
「読んで書く」更新をすると どうなるか
共有変数の更新
︓
X を読出す X+a を計算し
X へ書戻す
︓
︓
X を読出す X+b を計算し
X へ書戻す
︓
X=X+a X=X+b
プロセスA プロセスB
初期値0
共有 データ
X
共有変数の更新
︓
X を読出す X+a を計算し
X へ書戻す
︓
︓
X を読出す X+b を計算し
X へ書戻す
︓
X=X+a X=X+b
プロセスA プロセスB
初期値0
共有 データ
X
同時に⾛ると、どうなるか︖
共有変数の更新
タイミング例1 タイミング例2
↓ ↓
Aが読出す(0) Aが読出す(0) Aが書戻す(a) Bが読出す(0) Bが読出す(a) Aが書戻す(a) Bが書戻す(a+b) Bが書戻す(b)
↓ ↓
X=a+b X=b
︓
X を読出す X+a を計算
X へ書戻す
︓
︓
X を読出す X+b を計算
X へ書戻す
︓
X=X+a X=X+b
プロセスA プロセスB
初期値0
共有 データ
X
結果が違う
共有変数の更新
タイミング例1 タイミング例2
↓ ↓
Aが読出す(0) Aが読出す(0) Aが書戻す(a) Bが読出す(0) Bが読出す(a) Aが書戻す(a) Bが書戻す(a+b) Bが書戻す(b)
↓ ↓
X=a+b X=b
︓
X を読出す X+a を計算
X へ書戻す
︓
︓
X を読出す X+b を計算
X へ書戻す
︓
X=X+a X=X+b
プロセスA プロセスB
初期値0
共有 データ
X
本来なら0に a を足して b を足すので X は a+b になる
このタイミングだと X は b になる
結果が違う
共有変数の更新
タイミング例1 タイミング例2
↓ ↓
Aが読出す(0) Aが読出す(0) Aが書戻す(a) Bが読出す(0) Bが読出す(a) Aが書戻す(a) Bが書戻す(a+b) Bが書戻す(b)
↓ ↓
X=a+b X=b
︓
X を読出す X+a を計算
X へ書戻す
︓
︓
X を読出す X+b を計算
X へ書戻す
︓
X=X+a X=X+b
プロセスA プロセスB
初期値0
共有 データ
X
本来なら0に a を足して b を足すので X は a+b になる
このタイミングだと X は b になる
結果が違う
なぜか
共有変数の更新
順序がおかしい
↓ ↓
Aが読出す(0) Aが読出す(0) Aが書戻す(a) Bが読出す(0) Bが読出す(a) Aが書戻す(a) Bが書戻す(a+b) Bが書戻す(b)
↓ ↓
X=a+b X=b
共有変数の更新
順序がおかしい
↓ ↓
Aが読出す(0) Aが読出す(0) Aが書戻す(a) Bが読出す(0) Bが読出す(a) Aが書戻す(a) Bが書戻す(a+b) Bが書戻す(b)
↓ ↓
X=a+b X=b
Aが書き戻して いないので、
まだ 0 なのに Bが読出した
共有変数の更新
順序がおかしい
↓ ↓
Aが読出す(0) Aが読出す(0) Aが書戻す(a) Bが読出す(0) Bが読出す(a) Aが書戻す(a) Bが書戻す(a+b) Bが書戻す(b)
↓ ↓
X=a+b X=b
どうすればよいのか︖
Aが書き戻して いないので、
まだ 0 なのに Bが読出した
共有変数の更新
•
Aが先に読む+書くしてから、Bが読む+書くか、•
Bが先に読む+書くしてから、Aが読む+書くか、どちらかに制限する
共有変数の更新
•
Aが先に読む+書くしてから、Bが読む+書くか、•
Bが先に読む+書くしてから、Aが読む+書くか、どちらかに制限する (左の2つならOK)
↓ ↓ ↓
Aが読出す(0) Bが読出す(0) Aが読出す(0) Aが書戻す(a) Bが書戻す(b) Bが読出す(0) Bが読出す(a) Aが読出す(b) Aが書戻す(a) Bが書戻す(a+b) Aが書戻す(b+a) Bが書戻す(b)
↓ ↓ ↓
X=a+b X=a+b X=b
OK NG
共有変数の更新
•
Aが先に読む+書くしてから、Bが読む+書くか、•
Bが先に読む+書くしてから、Aが読む+書くか、どちらかに制限する
↓
•
Aの(読む+書く)の間は、Bはアクセスさせない•
Bの(読む+書く)の間は、Aはアクセスさせない共有変数の更新
•
Aが先に読む+書くしてから、Bが読む+書くか、•
Bが先に読む+書くしてから、Aが読む+書くか、どちらかに制限する
↓
•
Aの(読む+書く)の間は、Bはアクセスさせない•
Bの(読む+書く)の間は、Aはアクセスさせない| |
「相互排他」
排他の仕組=ロック
排他の仕組=ロック
•
共有データXを一方のプロセスがロックすると、解除するまで、
他のプロセスはアクセス(読書き)できない
排他の仕組=ロック
•
共有データXを一方のプロセスがロックすると、解除するまで、
他のプロセスはアクセス(読書き)できない
︓
X を読出す X+a を計算
X へ書戻す
︓
︓
X を読出す X+b を計算
X へ書戻す
︓
X=X+a X=X+b
プロセスA プロセスB
初期値0
共有 データ
X
ロック
解除
ロック
解除
この間は他のプロセスが 共有データXを 読書きできない
排他の仕組=ロック
•
共有データXを一方のプロセスがロックすると、解除するまで、
他のプロセスはアクセス(読書き)できない
︓
X を読出す X+a を計算
X へ書戻す
︓
︓
X を読出す X+b を計算
X へ書戻す
︓
X=X+a X=X+b
プロセスA プロセスB
初期値0
共有 データ
X
この間は他のプロセスが 共有データXを 読書きできない
ロック
解除
ロック
解除
資源確保
資源の解放 資源を占有
• プロセス(orスレッド)
が排他的な資源を 使いたくなる
• 空いていれば占有
(ロック)できる
相互排他と占有
プロセスA
(スレッドA)
実行
相互排他が 必要な資源
Aが占有
Aが資源を 使いたい ロックする
• プロセス(orスレッド)
が排他的な資源を 使いたくなる
• 空いていれば占有
(ロック)できる
• 使い終わったら解放
相互排他と占有
プロセスA
(スレッドA)
実行
相互排他が 必要な資源
Aが占有
Aが資源を 使いたい
実行
Aが資源を 解放する
ロックする
• プロセス(orスレッド)
が排他的な資源を 使いたくなる
• 空いていれば占有
(ロック)できる
• 他のプロセスは資源 が空くまで待たされる
(ブロックされる)
相互排他と占有
プロセスA
(スレッドA) プロセスB
(スレッドB)
実行
相互排他が 必要な資源
Aが占有 実行
Bも資源を 使いたい Aが資源を
使いたい ロックする
既にAが使用中
• プロセス(orスレッド)
が排他的な資源を 使いたくなる
• 空いていれば占有
(ロック)できる
• 他のプロセスは資源 が空くまで待たされる
(ブロックされる)
相互排他と占有
プロセスA
(スレッドA) プロセスB
(スレッドB)
実行
相互排他が 必要な資源
Aが占有 実行
Bも資源を 使いたい Aが資源を
使いたい
Bは待たされる
ブロック されている ロックする
既にAが使用中
• プロセス(orスレッド)
が排他的な資源を 使いたくなる
• 空いていれば占有
(ロック)できる
• 使い終わったら解放
• 他のプロセスは資源 が空くまで待たされる
(ブロックされる)
相互排他と占有
プロセスA
(スレッドA) プロセスB
(スレッドB)
実行
相互排他が 必要な資源
Aが占有 実行
Bも資源を 使いたい Aが資源を
使いたい
Bは待たされる
実行
Aが資源を 解放する
ブロック されている ロックする
• プロセス(orスレッド)
が排他的な資源を 使いたくなる
• 空いていれば占有
(ロック)できる
• 使い終わったら解放
• 他のプロセスは資源 が空くまで待たされる
(ブロックされる)
相互排他と占有
プロセスA
(スレッドA) プロセスB
(スレッドB)
実行
相互排他が 必要な資源
Aが占有 実行
Bも資源を 使いたい Aが資源を
使いたい
Bは待たされるBが占有
実行
Aが資源を 解放する
ブロック されている ロックする
空いたので ロックできる
• プロセス(orスレッド)
が排他的な資源を 使いたくなる
• 空いていれば占有
(ロック)できる
• 使い終わったら解放
• 他のプロセスは資源 が空くまで待たされる
(ブロックされる)
相互排他と占有
プロセスA
(スレッドA) プロセスB
(スレッドB)
実行
相互排他が 必要な資源
Aが占有 実行
Bも資源を 使いたい Aが資源を
使いたい
Bは待たされるBが占有
実行 実行
Aが資源を 解放する
Bが資源を 解放する
ブロック されている ロックする
空いたので ロックできる
ことば︓ クリティカルセクション
• 相互排他
= mutual exclusion 短縮してmutexと呼ぶ
• ロック = かぎ(錠)〜を掛け て他が入れない、占有
ことば︓ クリティカルセクション
• 相互排他
= mutual exclusion 短縮してmutexと呼ぶ
• ロック = かぎ(錠)〜を掛け て他が入れない、占有
• クリティカルセクション
(クリティカルリージョン)
||
プログラム中で、資源に排他 的にアクセスする部分のこと
プロセス(or スレッド)
資源に 関わらない コード部分
資源をロック 資源にアクセス
(1回とは限らない)
(ロックしたまま 何度もアクセス することも多い)
資源を解放
資源に 関わらない コード部分
資源使用中
この部分のコードをクリティカルセクションと呼ぶ
(脱線)ロックの実現
(脱線)ロックの実現
•
共有変数「ロック中」(使用中)を用意し、(脱線)ロックの実現
•
共有変数「ロック中」(使用中)を用意し、•
もし「1」なら使用中なので待つ(脱線)ロックの実現
•
共有変数「ロック中」(使用中)を用意し、•
もし「1」なら使用中なので待つ•
もし「0」なら空いているので「1」にして、使い始める 使い終わったら「0」に戻す
(脱線)ロックの実現
•
共有変数「ロック中」(使用中)を用意し、•
もし「1」なら使用中なので待つ•
もし「0」なら空いているので「1」にして、使い始める 使い終わったら「0」に戻す
•
問題点︓「ロック中」変数を共有メモリ上に取って
上の仕組を作ると ⇒ うまくいかない
(脱線)ロックの実現
•
共有変数「ロック中」がうまくいかない
プロセスA 共有変数ロックL
ロックの操作
ロックしたい Lを読んで 0ならOK
Lに1を書込む
プロセスB
初期値0
値1
ロックしたい Lを読んで 0ならOK
Lに1を書込む
ロックの操作
ロックできたと思い込む ロックできたと思い込む
(脱線)ロックの実現
•
共有変数「ロック中」がうまくいかない
•
Aが変数Lに 1 を書き 込まないうちに、Bが L を読出して
まだ空いていると思う
プロセスA 共有変数ロックL
ロックの操作
ロックしたい Lを読んで 0ならOK
Lに1を書込む
プロセスB
初期値0
値1
ロックしたい Lを読んで 0ならOK
Lに1を書込む
ロックの操作
ロックできたと思い込む ロックできたと思い込む
(脱線)ロックの実現
•
共有変数「ロック中」がうまくいかない
•
Aが変数Lに 1 を書き 込まないうちに、Bが L を読出して
まだ空いていると思う
•
AもBもロックできた と思い込むプロセスA 共有変数ロックL
ロックの操作
ロックしたい Lを読んで 0ならOK
Lに1を書込む
プロセスB
初期値0
値1
ロックしたい Lを読んで 0ならOK
Lに1を書込む
ロックの操作
ロックできたと思い込む ロックできたと思い込む
(脱線)ロックの実現
•
共有変数「ロック中」がうまくいかない
•
Aが変数Lに 1 を書き 込まないうちに、Bが L を読出して
まだ空いていると思う
•
AもBもロックできた と思い込むプロセスA 共有変数ロックL
ロックの操作
ロックしたい Lを読んで 0ならOK
Lに1を書込む
プロセスB
初期値0
値1
ロックしたい Lを読んで 0ならOK
Lに1を書込む
ロックの操作
ロックできたと思い込む ロックできたと思い込む
なぜ︖ ⇒ Aが「読んで書く」間に(書く前に)Bが読出すから
(脱線)ロックの実現〜解決策
1. ハードウェアに工夫して
「読む⇒書く」の動作を 不可分(その間他の操作を できない)にする
例︓Test & Set 命令など 2. 1CPU上での多プロセス
の場合に限って有効だが、
プロセス切替(割込み)を 起こさせない(禁止)よう にする
例︓割込み禁⽌による
プロセスA 共有変数ロックL
ロックの操作
ロックしたい Lを読んで 0ならOK
Lに1を書込む
プロセスB
初期値0
値1
ロックしたい Lを読んで 0ならOK
Lに1を書込む
ロックの操作
ロックできたと思い込む ロックできたと思い込む
排他制御の仕組のまとめ
•
共有データ(共有ファイルも)を「読んで書く」などしたいとき、
排他制御の仕組のまとめ
•
共有データ(共有ファイルも)を「読んで書く」などしたいとき、
その間で他プロセスがアクセスすると 動作の不統一が起こる
排他制御の仕組のまとめ
•
共有データ(共有ファイルも)を「読んで書く」などしたいとき、
その間で他プロセスがアクセスすると 動作の不統一が起こる
•
それを防ぐには排他制御の仕組のまとめ
•
共有データ(共有ファイルも)を「読んで書く」などしたいとき、
その間で他プロセスがアクセスすると 動作の不統一が起こる
•
それを防ぐには他プロセスが間に入って困る不可分の動作中は
排他制御の仕組のまとめ
•
共有データ(共有ファイルも)を「読んで書く」などしたいとき、
その間で他プロセスがアクセスすると 動作の不統一が起こる
•
それを防ぐには他プロセスが間に入って困る不可分の動作中は ロックによって排他すればよい
42
排他制御の必要性と
ロックによる排他制御の方法が 理解できましたか︖
次へ