んだ日記

ndaDayoの技術日記です

排他制御の原則と実現戦略 計算機システム概論より

前回は、排他制御の必要性についてまとめていきました。

nda-desu.hatenablog.com

並行処理を行う際に、なぜ排他制御が必要になるか?については前回で理解できました。

今回は、どのようにして排他制御を行うかの理論についてまとめていきます。

計算機システム概論 第16回「計算資源(CPU)の管理:排他制御の原則」 第16回ビデオ教材 - YouTube

本記事は↑の講義の学習用のまとめです。詳しくは↑をご視聴くださいませ。

クリティカルリージョン(Critical Region)

まずは、クリティカルリージョン(Critical Region)という概念について押さえていきます。

クリティカルリージョンとは、

共有資源の変更を行うプログラム

のことです。

具体例を見た方がわかりやすかったので、具体例をみていきます。

クリティカルリージョン(Critical Region)具体例

講義スライド(102)から引用

排他制御の必要性を説明する際に問題になった部分ですね。

色枠で囲まれているプログラムは、共有資源の変更を行っており、排他制御なしで並行処理を行うと、実行順によって不整合を起こすプログラムです。

このプログラムを、クリティカルCritical Region)と呼びます。

ロックによる排他制御無限後退

では、続いて排他制御のアプローチについてまとめていきます。 1つ目は、ロックによる排他制御です。

基本的な考え方は以下の通りです

1. 各資源 S 毎に共有メモリ上に一ビットの錠(Lock) を割り当てる.
2. Lock == 1 なら使用中,Lock == 0 なら資源使用可と約束.
3. Lock を取得する処理,Lock を解放する処理を作成.

このアプローチは、一見するとうまくいきそうな気がしますよね。

しかし、このアプローチは、

Lock自身が共有資源。
Lockの取得と解放もまたクリティカルリージョン
つまり、Lockについても排他制御をしないといけない

ということになってしまいます。

排他制御のアプローチのはずのLockを利用するためにさらに、排他制御をするという無限後退。。w

ということで、このロックによる排他制御ではうまくはいきません。

test and set 命令

では、どうするか?ですが、 test and set 命令を使えば解決します。

test and set 命令は、Lockなどの共有資源へのメモリアクセスを排除した状態で、読み込みと書き込みを実行します。一連の処理を不可分で実行するというわけですね。

このような処理をアトミックなメモリアクセスと呼びます。

今までのアプローチでは読み込みと書き込みをそれぞれの命令として実行していたため、実行順序によってデータの不整合を起こしてしまいました。

が、ハードウェアの命令として用意して、それを使用することでロックによる排他制御無限後退問題を解決するというわけですね。

test and set 命令をProducer-Consumer問題に適用してみる

process Producer
{
    while (TRUE) {
        while(!text-and-set(Lock));
        if (index == MAX)
        {
        }
        else {
            {data作成;}
            index = index + 1;
            Buffer[index] = data
        }
        Lock = 0;
    }
}

このコードは以下のようなロジックで動きます。

  1. text-and-set(Lock)で、Lockが取得できるまで待機する
  2. Lockが取得できたらクリティカルリージョン(Critical Region)を処理
  3. Lockを解放

これなら、並行処理でも不整合が起きることはないっすね。

Busy wait 問題

さて、text-and-set命令を組み込むことで、並行処理における不整合の問題をクリアすることができましたが、まだ問題があります。

それが、Busy wait 問題です。

Busy wait 問題とは

別なプロセスがロックを持っている間は,他のプロセスはロックを取得するために test-and-set を実行し続け,CPU の無駄となる.

という問題です。

これは、漏れそうな時のトイレに例えるとわかりやすいですね。

トイレが1個しかない場合に誰かが使用している間は、何度も開いたかどうかを確認しにいかないといけないですよね。

さらに、このBusy wait 問題、CPU の無駄というだけではなく、実際に並行処理を実現していることになっていないという点でもアカンです

デッドロック問題

続いて、デッドロック問題についても見ていきましょう。

先程の例では、Lock変数が1つだけ存在するという前提で記述していましたが、1つだけだとBusy wait が発生してしまうので、Lock変数を細かく分割して複数作ったとしましょう。

うまく動きそうな気がしますが、以下のような状態に陥る可能性があります。

どちらのプロセスも、お互いのLockの解放を永遠に待ち続けるという状態です。

まとめ

以上で、排他制御の原則と実現戦略について見ていきました。

text-and-set命令を学んだ時には、あーもうこれで解決か、シンプルで素晴らしい解決策だなーと興奮したですが、いざ適用するとBusy wait 問題、デッドロック問題が孕んでいることがわかり、より興奮しました。

ここらへんの話題は、ほんとにワクワクしますね。

次回は、排他制御の最終章です。張り切っていきましょう。

僕から以上。あったかくして寝ろよ

引用させて頂いた講義スライド http://www.pllab.riec.tohoku.ac.jp/~ohori/texts/SystemSoftware2019SlidesDistRev.pdf