カーネル同期の概要
(一):臨界区と競争条件
臨界領域(臨界セグメントとも呼ばれる)とは、共有データへのアクセスと操作のコードセグメントである.複数の実行スレッドが同じリソースに同時にアクセスするのは通常安全ではないが、臨界領域での同時アクセスを避けるために、プログラマはこれらのコード原子の実行を保証しなければならない.すなわち、実行が終了する前に操作が中断されてはならない.2つの実行スレッドが同じ臨界領域で同時に実行される可能性がある場合、これがプログラムに含まれるバグである.もしこのような状況が実際に発生したら、私たちは彼が競争条件であると判断した.このようなネーミングは、ここにスレッド競争が存在するためである.同時発生を回避し、競争条件を同期と呼ぶことを防止する.
1:単一変数
ここで、まず特殊な計算例を見る.非常に簡単な共有資源を考慮する:グローバル整数変数と簡単な臨界領域.その中の操作は整数変数の値を1増加するだけである.
i++;
この操作は、以下の動作と同様の機械命令シーケンスに変換することができる.
現在の変数iの値を取得し、1つのレジスタにコピーしてレジスタの値に1を加えてiの新しい値をメモリに書き込む
2つの実行スレッドが同時に臨界領域に入ると仮定し、iの初期値が7である場合、私たちが望む結果は以下のように(各行は時間単位を表す):
これは私たちが望んでいることですが、実際の運行状況は次のようになります.
これは私たちが望んでいる結果ではありませんが、実際にはこのような現象も発生する可能性があります.このような状況の解決も比較的簡単です.-私たちはこれらの命令を分割できない全体として実行するだけでいいです.多くのプロセッサは原子の読み取り変数を提供し、変数を増加します.次に変数を書き戻し、このような命令を使用するといくつかの問題を解決することができます.この命令を使用する唯一の可能性のある結果は:
あるいは反対に
2つの原子操作の実行は、プロセッサが物理的に不可能であることを確保するため、まったく不可能である.
(二):ロック
ロックは多種多様な形式があり、またロックの粒度もそれぞれ異なる--Linux自身はいくつかの異なるロックメカニズムを実現した.各種のロックメカニズムの違いは主に:ロックがすでに他のスレッドに所有されているので、使用できない時の行為表現--いくつかのロックが競合する時に簡単に実行して待つことである.他のロックは、現在のタスクの睡眠にロックが利用可能であることを知らせる.
1:同時実行の原因
ユーザ空間が同期する必要があるのは、ユーザプログラムがスケジューラによってプリエンプトされ、再スケジューラされるためである.ユーザプロセスがいつでもプリエンプトされる可能性があり、スケジューラがプロセッサ上で実行する別の優先度の高いプロセスを選択する可能性があるため、1つのプログラムが臨界領域にある場合、非自発的に占有された.新しいスケジューリングのプロセスがその後も同じ臨界領域(例えば,この2つのプロセスが共有メモリを操作するか,同じファイル記述子に書き込むか)に入ると,前後の2つのプロセスが互いに競合する.また,信号処理は非同期で発生するため,単一スレッドの複数のプロセスがファイルを共有しても,あるいは、同じプログラムの内部で信号を処理することで、競合条件が生じる可能性もある.
対称マルチプロセッサをサポートする機械が1台あれば、2つのプロセスは本当に臨界領域で同時に実行することができ、このタイプを真同時と呼ぶ.
カーネルには、同時実行の可能性と同様の理由があります.割り込み-割り込みはほとんどいつでも非同期で発生し、現在実行中のコードソフト割り込みとtaskletをいつでも中断することができます.カーネルは、いつでもソフト割り込みとtaskletを起動またはスケジュールし、現在実行中のコードカーネルプリエンプトを中断することができます.カーネルにプリエンプト性があるため、したがって、カーネル内のタスクは、別のタスクによってスリープとユーザ空間の同期を奪われる可能性があります.カーネルで実行されるプロセスがスリープになる可能性があります.これにより、スケジューラが起動し、新しいユーザプロセスをスケジューリングして対称マルチプロセッサを実行できます.2つ以上のプロセッサでコードを同時に実行できます.
割り込みプロセッサで同時アクセスを回避できるセキュリティコードを割り込みセキュリティコードと呼ぶ.対称マルチプロセッサの機器において同時アクセスを回避できるセキュリティコードをSMPセキュリティコード(SMP-safe)と呼ぶ.カーネルプリエンプト時に同時アクセスを回避できるセキュリティコードをプリエンプトセキュリティコードと呼ぶ.
2:それらのデータにロックをかける必要がある
他のスレッドがこれらのデータにアクセスできる場合は、これらのデータにロックをかけます.他の何でも彼を見ることができるなら、彼をロックしなければなりません.コードにロックするのではなく、データにロックしなければなりません.
(三)デッドロック
デッドロックの発生には一定の条件が必要である:1つ以上の実行スレッドと1つ以上のリソースが必要であり、各スレッドはその中の1つのリソースを待っているが、すべてのリソースはすでに占有されている.すべてのスレッドは互いに待っているが、彼らは永遠に占有されたリソースを解放しない.そこで、いかなるスレッドも継続できない.これはデッドロックの発生を意味する.
最も簡単なデッドロックの例は自己デッドロックである:実行スレッドが自分のすでに持っているロックを獲得しようとすると、彼はロックが解放されるのを待たなければならないが、彼はこのロックを待っているので、自分は永遠に場所を解放する機会がなく、最終的にはデッドロックである.
いくつかの簡単なルールは、デッドロックを回避するのに非常に役立ちます.
1:順番にロックをかけて、できるだけ反対の順序でロックを解除する.ネストされたロックを使用する場合、同じ順序でロックを取得することを保証しなければならない.これにより、致命的な抱擁タイプのデッドロックを阻止することができる.
(四):競合と拡張性
ロックの競合、または単に競合とは、ロックが占有する場合に、他のスレッドがロックを取得しようとすることを意味する.1つのロックが高い競合状態にあるということは、複数の他のスレッドがロックの取得を待っていることを意味する.
拡張性はシステムの拡張性のメトリックである.
臨界領域(臨界セグメントとも呼ばれる)とは、共有データへのアクセスと操作のコードセグメントである.複数の実行スレッドが同じリソースに同時にアクセスするのは通常安全ではないが、臨界領域での同時アクセスを避けるために、プログラマはこれらのコード原子の実行を保証しなければならない.すなわち、実行が終了する前に操作が中断されてはならない.2つの実行スレッドが同じ臨界領域で同時に実行される可能性がある場合、これがプログラムに含まれるバグである.もしこのような状況が実際に発生したら、私たちは彼が競争条件であると判断した.このようなネーミングは、ここにスレッド競争が存在するためである.同時発生を回避し、競争条件を同期と呼ぶことを防止する.
1:単一変数
ここで、まず特殊な計算例を見る.非常に簡単な共有資源を考慮する:グローバル整数変数と簡単な臨界領域.その中の操作は整数変数の値を1増加するだけである.
i++;
この操作は、以下の動作と同様の機械命令シーケンスに変換することができる.
現在の変数iの値を取得し、1つのレジスタにコピーしてレジスタの値に1を加えてiの新しい値をメモリに書き込む
2つの実行スレッドが同時に臨界領域に入ると仮定し、iの初期値が7である場合、私たちが望む結果は以下のように(各行は時間単位を表す):
1 2
i(7) --------
i(7->8) --------
i(8) --------
--------- i(8)
--------- i(8->9)
--------- i(9)
これは私たちが望んでいることですが、実際の運行状況は次のようになります.
1 2
i(7) i(7)
i(7->8) ---------
------------- i(7->8)
i(8) -----------
------------ i(8)
これは私たちが望んでいる結果ではありませんが、実際にはこのような現象も発生する可能性があります.このような状況の解決も比較的簡単です.-私たちはこれらの命令を分割できない全体として実行するだけでいいです.多くのプロセッサは原子の読み取り変数を提供し、変数を増加します.次に変数を書き戻し、このような命令を使用するといくつかの問題を解決することができます.この命令を使用する唯一の可能性のある結果は:
1 2
i(7->8) ---------
-------------- i(8->9)
あるいは反対に
1 2
-------- i(7->8)
i(8->9) ---------
2つの原子操作の実行は、プロセッサが物理的に不可能であることを確保するため、まったく不可能である.
(二):ロック
ロックは多種多様な形式があり、またロックの粒度もそれぞれ異なる--Linux自身はいくつかの異なるロックメカニズムを実現した.各種のロックメカニズムの違いは主に:ロックがすでに他のスレッドに所有されているので、使用できない時の行為表現--いくつかのロックが競合する時に簡単に実行して待つことである.他のロックは、現在のタスクの睡眠にロックが利用可能であることを知らせる.
1:同時実行の原因
ユーザ空間が同期する必要があるのは、ユーザプログラムがスケジューラによってプリエンプトされ、再スケジューラされるためである.ユーザプロセスがいつでもプリエンプトされる可能性があり、スケジューラがプロセッサ上で実行する別の優先度の高いプロセスを選択する可能性があるため、1つのプログラムが臨界領域にある場合、非自発的に占有された.新しいスケジューリングのプロセスがその後も同じ臨界領域(例えば,この2つのプロセスが共有メモリを操作するか,同じファイル記述子に書き込むか)に入ると,前後の2つのプロセスが互いに競合する.また,信号処理は非同期で発生するため,単一スレッドの複数のプロセスがファイルを共有しても,あるいは、同じプログラムの内部で信号を処理することで、競合条件が生じる可能性もある.
対称マルチプロセッサをサポートする機械が1台あれば、2つのプロセスは本当に臨界領域で同時に実行することができ、このタイプを真同時と呼ぶ.
カーネルには、同時実行の可能性と同様の理由があります.割り込み-割り込みはほとんどいつでも非同期で発生し、現在実行中のコードソフト割り込みとtaskletをいつでも中断することができます.カーネルは、いつでもソフト割り込みとtaskletを起動またはスケジュールし、現在実行中のコードカーネルプリエンプトを中断することができます.カーネルにプリエンプト性があるため、したがって、カーネル内のタスクは、別のタスクによってスリープとユーザ空間の同期を奪われる可能性があります.カーネルで実行されるプロセスがスリープになる可能性があります.これにより、スケジューラが起動し、新しいユーザプロセスをスケジューリングして対称マルチプロセッサを実行できます.2つ以上のプロセッサでコードを同時に実行できます.
割り込みプロセッサで同時アクセスを回避できるセキュリティコードを割り込みセキュリティコードと呼ぶ.対称マルチプロセッサの機器において同時アクセスを回避できるセキュリティコードをSMPセキュリティコード(SMP-safe)と呼ぶ.カーネルプリエンプト時に同時アクセスを回避できるセキュリティコードをプリエンプトセキュリティコードと呼ぶ.
2:それらのデータにロックをかける必要がある
他のスレッドがこれらのデータにアクセスできる場合は、これらのデータにロックをかけます.他の何でも彼を見ることができるなら、彼をロックしなければなりません.コードにロックするのではなく、データにロックしなければなりません.
(三)デッドロック
デッドロックの発生には一定の条件が必要である:1つ以上の実行スレッドと1つ以上のリソースが必要であり、各スレッドはその中の1つのリソースを待っているが、すべてのリソースはすでに占有されている.すべてのスレッドは互いに待っているが、彼らは永遠に占有されたリソースを解放しない.そこで、いかなるスレッドも継続できない.これはデッドロックの発生を意味する.
最も簡単なデッドロックの例は自己デッドロックである:実行スレッドが自分のすでに持っているロックを獲得しようとすると、彼はロックが解放されるのを待たなければならないが、彼はこのロックを待っているので、自分は永遠に場所を解放する機会がなく、最終的にはデッドロックである.
いくつかの簡単なルールは、デッドロックを回避するのに非常に役立ちます.
1:順番にロックをかけて、できるだけ反対の順序でロックを解除する.ネストされたロックを使用する場合、同じ順序でロックを取得することを保証しなければならない.これにより、致命的な抱擁タイプのデッドロックを阻止することができる.
(四):競合と拡張性
ロックの競合、または単に競合とは、ロックが占有する場合に、他のスレッドがロックを取得しようとすることを意味する.1つのロックが高い競合状態にあるということは、複数の他のスレッドがロックの取得を待っていることを意味する.
拡張性はシステムの拡張性のメトリックである.