2017-08-18 9 views
3

Cでは、シグナルハンドラはタイプvolatile sig_atomic_tの変数にしかアクセスできません。 perlでは、この種のシグナルハンドラを実行するのは安全です(そしてアトミック)?シグナルハンドラ内の共有変数にアクセス/変更することは安全ですか?

my $p = 0; 

$SIG{CHLD} = sub { 
    while (waitpid(-1, WNOHANG) > 0) { 
     $p--; 
    } 
}; 

私のメインスレッドが=++または+=をしているよう$pで作業している間。

私はperl use Safe-Signalsを知っていますが、単純な++または--の単一オペコードですか? 1-opcodeはどの言語演算子ですか?

私は、操作が何であるのかという意味で、$pのコンテンツが壊れないようにしています。

+0

「安全」なのかどうかにもよると思います。私は、 'SIGCHLD'ハンドラのハッシュへの代入に基づいてフロー制御を使用する長期実行型(ただし重要ではありませんが)コードを持っています。いくつかのソケット読み取りはシグナルハンドラによって中断されますが(割り当てのためではありません)、ハンドラ自体には問題はなく、予期しないこともありません。しかし、単一のオペコードについてはわかりません。 – zdim

+0

ハッシュの更新が複数のオペコード(アイデアなし)で行われている場合、それを使って作業していて途中で中断した場合、どうなりますか? –

+0

ハッシュにキーと値のペアを追加するのは複雑で、1つのオペコードではないことは間違いありません。 _that_が中断された場合、良いことは起こりません。しかし、私は、変数に準備値を割り当てるだけのハンドラのコードが中断されるという非常に小さなチャンスがあると思います(私はそれがどう起こるのか分かりません)。それがもっとしているなら、それは違う。ご注意:私は必要なだけのことをするのが最善だと思います。 – zdim

答えて

4

%SIGのシグナルにサブを割り当てると、Perlはカウンタをインクリメントするシグナルハンドラをインストールします。このカウンタは、Perlオペコードの間でチェックされます。 [1]その時だけ、Perlサブ・コールが呼び出されます。

プリインクリメント、ポストインクリメント、プリデクリメントおよびポストデクリメントはすべてPerlオペコードであるため、信号によって中断されることはありません。

$ perl -MO=Concise,-exec -e'my $x; ++$x; --$x; $x++; $x--;' 
1 <0> enter 
2 <;> nextstate(main 1 -e:1) v:{ 
3 <0> padsv[$x:1,2] vM/LVINTRO 
4 <;> nextstate(main 2 -e:1) v:{ 
5 <0> padsv[$x:1,2] sRM 
6 <1> preinc vK/1 
7 <;> nextstate(main 2 -e:1) v:{ 
8 <0> padsv[$x:1,2] sRM 
9 <1> predec vK/1 
a <;> nextstate(main 2 -e:1) v:{ 
b <0> padsv[$x:1,2] sRM 
c <1> preinc[t2] vK/1 
d <;> nextstate(main 2 -e:1) v:{ 
e <0> padsv[$x:1,2] sRM 
f <1> predec[t3] vK/1 
g <@> leave[1 ref] vKP/REFC 
-e syntax OK 

また$pが、それは安全ですかどうかを決定するためにシグナルハンドラの外で使用されている方法を確認する必要があります。例えば、シグナルハンドラの外側にあるコードが中断する可能性があるため、次のコードを実行すると問題が発生します。

$p = $p - 1; 

これは安全です:

my %children; 

$SIG{CHLD} = sub { 
    local ($?, $!, $^E); 
    while ((my $pid = waitpid(-1, WNOHANG)) > 0) { 
     my $child = $children{$pid} 
     or next; # ?!? 

     $child->{exit_status} = $?; 
    } 
};  

while (1) { 
    ... 

    for my $pid (keys(%children)) { 
     my $child = $children{$pid}; 
     defined(my $exit_status = $child->{exit_status}) 
     or next; 

     delete($children{$pid}); 

     ... 
    } 

    ... 
} 

  1. 私はそれがPerlのの最近のバージョンでさえ少ない粒状行われていると思います。
+0

私の答えを更新しました。 – ikegami

関連する問題