シグナル ハンドラー内では、非同期セーフ関数のみを呼び出す必要があると言われています。私の質問は、非同期安全性を構成するものは何ですか? 再入可能でスレッドセーフな関数は非同期セーフだと思いますか? それともいいえ?
2 に答える
再入可能性とスレッド セーフは、これとほとんどまたはまったく関係がありません。これらの機能の副作用、状態、および中断は重要な事実です。
非同期セーフ関数[GNU Pth]
関数は、シグナル ハンドラー コンテキスト内から副作用なく安全に呼び出すことができる場合、非同期セーフまたは非同期シグナル セーフです。つまり、一貫性のない状態を引き起こすことなく、順不同で直線的に実行するには、いつでも中断できる必要があります。また、グローバル データ自体が不整合な状態にある可能性がある場合にも、適切に機能する必要があります。いくつかの非同期セーフ操作を次に示します。
- 関数を呼び出して
signal()
シグナル ハンドラを再インストールする- 無条件に
volatile sig_atomic_t
変数を変更します (この型への変更はアトミックであるため)- 関数を呼び出して
_Exit()
プログラムの実行を即座に終了する- 実装で指定された非同期セーフ関数を呼び出す
移植可能な非同期セーフの関数はほとんどありません。関数が他の操作を実行する場合、その関数はおそらく移植性の高い非同期セーフではありません。
経験則は次のとおりです - シグナルハンドラーからいくつかの条件変数のみを通知します (futex/pthread 条件、epoll ループの起動など)。
アップデート:
EmployedRussianが示唆したように、電話でさえpthread_cond_signal
悪い考えです。最近のソースコードを確認したところ、eglibc
ロック/ロック解除のペアが含まれています。したがって、デッドロックの可能性が生じます。これにより、他のスレッドに通知するためのいくつかのオプションが残ります。
- を使用し
eventfd
ます。 - グローバル アトミック変数を変更し、SA_RESTART が設定されておらず、他のスレッドがアトミックをチェックすることを期待します。
独自のコードの場合、はい、リエントラントとスレッドセーフが必要な特性です。信号処理メカニズムの設定方法によっては、信号ハンドラー自体が別の信号によって中断される可能性があるためです。一般に、シグナルハンドラー内で行う作業はできるだけ少なくするようにしてください。通常のプログラムフローで特別なコードをトリガーするようにフラグを設定するだけで、おそらく実行する必要があります。
呼び出す可能性のあるOSの関数についてman 7 signal
は、安全に呼び出すことができる関数のリストを確認してください。malloc()
とfree()
はリストにないことに注意してください。pthread同期APIもリストに含まれていませんが、安全に呼び出すことができるAPIもあると思います。そのため、シグナルハンドラーでグローバルフラグを安全に設定できます。