2

私は最近、Advanced Linux Programmingという名前の本を研究していましたが、この質問に遭遇しました。この本はsig_atomic_t、シグナルハンドラー関数でグローバルフラグまたはカウンターを設定した場合に、コンテキストスイッチが発生しないように変数型を使用する必要があると述べています。算術演算(すなわち++)とそれらをレジスタに保存します。

私の質問はsig_atomic_t、別のタイプを使用せずに使用すると、コンテキストスイッチが発生するとどうなるでしょうか。たとえば、プログラムが戻って後で保存するだけです。誰かが私たちのコードを不安定にしたりバグを犯したりするシナリオを教えてもらえますか?

4

3 に答える 3

2

説明するシナリオ(メモリからレジスタへの読み取り、レジスタの更新、メモリへの書き込み、およびこれらの操作のいずれかの間でコンテキストスイッチが発生する)で実行するリスクは、他のコンテキストで行われた更新を失う可能性があることです。

例えば:

main context:
  read i (=10) from memory to register R1
  add 5 to R1
    <interrupt. Switch to interrupt context>
    read i (=10) from memory to register R1
    add 10 to R1
    write R1 to i in memory (i = 20)
    <end of interrupt. Back to main context>
  write R1 to i in memory (i = 15)

ご覧のとおり、割り込みからの更新は失われています。

タイプがメモリに書き込むために複数の操作を必要とし、書き込み操作の途中で割り込みが発生した場合、さらに大きな問題が発生します。

例えば:

main context:
  read first half of i (=10) from memory to register R1
  read second half of i (=10) from memory to register R2
  add 5 to R1/R2 pair
  write R1 to first half of i in memory
    <interrupt. Switch to interrupt context>
    read first half of i (= ??) from memory to register R1
    read second half of i (= ??) from memory to register R2
    add 10 to R1/R2 pair
    write R1 to first half of i in memory
    write R2 to second half of i in memory
    <end of interrupt. Back to main context>
  write R2 to second half of i in memory

ここでは、私が最終的にどのような値になるかはわかりません。

sig_atomic_tを使用すると、タイプがアトミックな読み取り/書き込み操作を使用することが保証されているため、この2番目の問題は発生しません。

于 2010-10-08T10:51:20.550 に答える
2

安全でない動作につながる例を次に示します。

int64_t a = 2^32-1;

void some_signal_handler()
{
   ++a;
}

void f()
{
  if( a == 0 )
    printf("a is zero");
}

32ビットアーキテクチャを想定します。変数aは、実際には2つの32ビット整数として格納され、{0,2^32-1}として始まります。最初にfはaの上半分を0として読み取ります。次にシグナルが発生し、実行がシグナルハンドラーに切り替わります。aを2^32-1から2^32にインクリメントします。aの新しい値は{1,0}です。シグナルハンドラが完了し、fの実行が続行されます。fはaの下半分を0として読み取ります。全体として、fは意図されていなかったゼロとしてaを読み取りました。

于 2010-10-08T10:52:00.950 に答える
1

シグナルハンドラーから変数を書き込むよりも良い解決策は、パイプを開いたままにして、シグナルハンドラーからパイプに値を書き込むことです。これには、競合状態なしで(パイプの読み取り側で選択している限り)選択をウェイクアップできるという利点があり、メインで信号のメイン処理のほとんどを実行できるようになります。 select loopは、必要なライブラリ関数を自由に使用できる場所です。

于 2010-10-08T15:13:10.437 に答える