「クリティカルセクション」の版間の差分

削除された内容 追加された内容
NDR (会話 | 投稿記録)
m 記事名。
Aqv (会話 | 投稿記録)
例を追加、読みにくい文章なので読みやすい文体にしてくれる人求む
2行目:
クリティカルセクションでは、排他を行うなどして[[アトミック性]]を確保する必要がある。
 
クリティカルセクションの処理は複数の命令からなる。逆にいえば、1つの命令、つまり[[CPU]]にとって1回の処理で終わるものはクリティカルセクションに入れる''必要が無い''。
{{stub}}
 
==例==
''以下の例はCPUが1つである場合である。''
ウェブページの来訪者数を表す[[カウンター]]のプログラムを例にとって説明する。カウンターのプログラムはおおまかに次の処理からなる。
#[[ディスク]]等の[[記憶装置]]から現在のカウンタの値を読み出す
#カウンタの値を1増やす
#カウンタの値を記憶装置に書き戻す
実際はこの命令それぞれが複数の細かい命令からなるのが普通だ。
 
===クリティカルセクションを使用しない場合===
ここで、現在ディスクに書き込まれているカウンタの値が'''100'''だったとする。
ユーザーAがこのウェブページを訪れ、カウンタプログラムの'''スレッドA'''が実行しはじめたとしよう。スレッドAは'''1'''でカウンタの値を読み出し(値は'''100''')、'''2'''で値を増やす(値は'''101''')。次に'''3'''で値を書き戻すのだが、ここでユーザーBがウェブページを訪れたことによる別の'''スレッドB'''が実行され、すぐさま[[コンテキストスイッチ]]が起きて処理がスレッドBに移されたとする。スレッドBがカウンタの値を読み出すと値は'''100'''になる。何故ならば、''スレッドAがまだ3の処理を行っていないため、ディスク上の値は変化してない''からである。そして、スレッドBは値を増やし、その結果の'''101'''という値をディスクに書き込み、スレッドを終了する。
次に再びスレッドAへ処理がうつり、スレッドAは3の処理を行い、ディスクには'''101'''という値が書き込まれて、スレッドAも処理を終える。
 
結果として、ユーザーAとユーザーBの2人がページを訪れたので、カウンタの値は2増えて'''102'''にならなければならないのに、結果としてディスクに書き込まれてる値は'''101'''となる。
 
以上の処理を時間に沿ってまとめたものが以下の表である。
<table border="1" cellpadding="2">
<tr><th>ディスク上の値</th><th>スレッドA(値)</th><th>スレッドB(値)</th></tr>
<tr><td>'''100'''</td><td>スレッド発生</td><td></td></tr>
<tr><td>100</td><td>処理1(100)</td><td></td></tr>
<tr><td>100</td><td>処理2(101)</td><td></td></tr>
<tr><td>100</td><td rowspan="5">待機</td><td>スレッド発生</td></tr>
<tr><td>'''100'''</td><td>処理1(100)</td></tr>
<tr><td>100</td><td>処理2(101)</td></tr>
<tr><td>'''101'''</td><td>処理3(101)</td></tr>
<tr><td>101</td><td>スレッド終了</td></tr>
<tr><td>'''101'''</td><td>処理3(101)</td><td></td></tr>
<tr><td>101</td><td>スレッド終了</td><td></td></tr>
</table>
 
===クリティカルセクションを使用した場合===
クリティカルセクションとは、'''1つのスレッドのみが使用権を得ることができるプログラム上の処理領域'''と説明できるだろう。
 
あるスレッドがクリティカルセクションに入っている間は、別のスレッドはクリティカルセクションに入ることができない。普通はそのスレッドは待機状態になる。
 
このカウンタプログラムの場合、プログラムの最初、つまり上の場合でいうと処理1の前に'''クリティカルセクションに入る'''という処理を付け加える必要がある。そして、スレッドが終了する前に'''クリティカルセクションから出る'''という処理を付け加えれば完了だ。
 
ここで、先ほどと同様に'''スレッドA'''が処理1、処理2を終わらせて処理3を実行する前に、'''スレッドB'''が発生したとする。しかし、ここで既にスレッドAがクリティカルセクションに入っているため、スレッドBは処理を開始できないため待機状態となる。そしてスレッドAが処理を終え、クリティカルセクションから出るとスレッドBが再開する。結果として、意図したとおりの正しい動作になる。
 
以上の処理を時間に沿ってまとめたものが以下の表である。''なおクリティカルセクションは'''''CS'''''と略している。''
<table border="1" cellpadding="2">
<tr><th>ディスク上の値</th><th>スレッドA(値)</th><th>スレッドB(値)</th><th>'''CS'''の所有者</th></tr>
<tr><td>'''100'''</td><td>スレッド発生</td><td></td><td></td></tr>
<tr><td>100</td><td>'''CS'''に入る</td><td></td><td rowspan="6">スレッドA</td></tr>
<tr><td>100</td><td>処理1(100)</td><td></td></tr>
<tr><td>100</td><td>処理2(101)</td><td></td></tr>
<tr><td>100</td><td rowspan="2">待機</td><td>スレッド発生</td></tr>
<tr><td>100</td><td>'''CS'''''へ入ることに失敗''</td></tr>
<tr><td>'''101'''</td><td>処理3(101)</td><td rowspan="2">待機</td></tr>
<tr><td>101</td><td>'''CS'''から出て、スレッド終了</td><td></td></tr>
<tr><td>101</td><td></td><td>'''CS'''に入る</td><td rowspan="4">スレッドB</td></tr>
<tr><td>101</td><td></td><td>処理1(101)</td></tr>
<tr><td>101</td><td></td><td>処理2(102)</td></tr>
<tr><td>'''102'''</td><td></td><td>処理3(102)</td></tr>
<tr><td>102</td><td></td><td>'''CS'''から出て、スレッド終了</td><td></td></tr>
</table>
 
{{comp-stub}}