クリティカルセクション
クリティカルセクション(Critical section)とは、計算機上において、単一のリソースに対して、複数の処理が同時期に実行されると、破綻をきたす部分を指す。クリティカルセクションにおいては、排他制御を行うなどしてアトミック性を確保する必要がある。
リソースの同一性が保証されなくなる可能性がある場合は、クリティカルセクションでは常に排他制御を行う必要がある。
クリティカルセクションの排他制御ではデッドロックに注意する必要がある。
例
ウェブページの来訪者数を表すカウンタのプログラムを例にとって説明する。カウンターのプログラムはおおまかに次の処理からなる。
実際はこの命令それぞれが複数の細かい命令からなるのが普通だ。
排他制御を使用しない場合
ここで、現在ディスクに書き込まれているカウンタの値が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となる。
以上の処理を時間に沿ってまとめたものが以下の表である。
ディスク上の値 | スレッドA(値) | スレッドB(値) |
---|---|---|
100 | スレッド発生 | |
100 | 処理1(100) | |
100 | 処理2(101) | |
100 | 待機 | スレッド発生 |
100 | 処理1(100) | |
100 | 処理2(101) | |
101 | 処理3(101) | |
101 | スレッド終了 | |
101 | 処理3(101) | |
101 | スレッド終了 |
排他制御を使用した場合
排他制御をしたクリティカルセクションとは、1つのスレッドのみが使用権を得ることができるプログラム上の処理領域である。
あるスレッドが排他制御をしたクリティカルセクションに入っている間は、別のスレッドはクリティカルセクションに入ることができない。普通はそのスレッドは待機状態になる。
このカウンタプログラムの場合、プログラムの最初、つまり上の場合でいうと処理1の前に排他制御をしてクリティカルセクションに入るという処理を付け加える必要がある。そして、スレッドが終了する前に排他制御を解放してクリティカルセクションから出るという処理を付け加えれば完了だ。
ここで、先ほどと同様にスレッドAが処理1、処理2を終わらせて処理3を実行する前に、スレッドBが発生したとする。しかし、ここで既にスレッドAがクリティカルセクションに入っているため、スレッドBは処理を開始できないため待機状態となる。そしてスレッドAが処理を終え、クリティカルセクションから出るとスレッドBが再開する。結果として、意図したとおりの正しい動作になる。
以上の処理を時間に沿ってまとめたものが以下の表である。なおクリティカルセクションはCSと略している。
ディスク上の値 | スレッドA(値) | スレッドB(値) | CSの所有者 |
---|---|---|---|
100 | スレッド発生 | ||
100 | CSに入る | スレッドA | |
100 | 処理1(100) | ||
100 | 処理2(101) | ||
100 | 待機 | スレッド発生 | |
100 | CSへ入ることに失敗 | ||
101 | 処理3(101) | 待機 | |
101 | CSから出て、スレッド終了 | ||
101 | CSに入る | スレッドB | |
101 | 処理1(101) | ||
101 | 処理2(102) | ||
102 | 処理3(102) | ||
102 | CSから出て、スレッド終了 |