まず、ミューテックスは通常、非同期セーフとは見なされないことを認識しています。sigprocmask
この質問は、非同期シグナルとシグナルハンドラーを備えたマルチスレッドプログラムでミューテックスを安全にするための使用に関するものです。
概念的に次のようなコードがあります。
struct { int a, b; } gvars;
void sigfoo_handler(int signo, siginfo_t *info, void *context) {
if(gvars.a == 42 || gvars.b == 13) {
/* run a chained signal handler */
}
}
/* called from normal code */
void update_gvars(int a, int b) {
gvars.a = a;
gvars.b = b;
}
gvars
は大きすぎて単一に収まらないグローバル変数ですsig_atomic_t
。通常のコードで更新され、シグナルハンドラから読み取られます。制御されるコードは連鎖信号ハンドラーであるため、信号ハンドラーコンテキストで実行する必要があります(info
またはを使用する場合がありますcontext
)。したがって、すべてのアクセスは、gvars
ある種の同期メカニズムを介して制御する必要があります。複雑なことに、プログラムはマルチスレッドであり、どのスレッドも。を受け取る可能性がありますSIGFOO
。
質問:(sigprocmask
またはpthread_sigmask
)とを組み合わせることで、次のようなコードを使用して同期を保証するpthread_mutex_t
ことはできますか?
struct { int a, b; } gvars;
pthread_mutex_t gvars_mutex;
void sigfoo_handler(int signo, siginfo_t *info, void *context) {
/* Assume SIGFOO's handler does not have NODEFER set, i.e. it is automatically blocked upon entry */
pthread_mutex_lock(&gvars_mutex);
int cond = gvars.a == 42 || gvars.b == 13;
pthread_mutex_unlock(&gvars_mutex);
if(cond) {
/* run a chained signal handler */
}
}
/* called from normal code */
void update_gvars(int a, int b) {
sigset_t set, oset;
sigemptyset(&set);
sigaddset(&set, SIGFOO);
pthread_sigmask(SIG_BLOCK, &set, &oset);
pthread_mutex_lock(&gvars_mutex);
gvars.a = a;
gvars.b = b;
pthread_mutex_unlock(&gvars_mutex);
pthread_sigmask(SIG_SETMASK, &oset, NULL);
}
ロジックは次のようになります。内sigfoo_handler
では、SIGFOO
がブロックされるため、を中断することはできませんpthread_mutex_lock
。内update_gvars
では、保護されたクリティカル領域SIGFOO
中に現在のスレッドで発生させることはできないため、どちらも中断することはできません。他のシグナルがないと仮定すると(そして問題となる可能性のある他のシグナルを常にブロックできる)、ロック/ロック解除は常に現在のスレッドで通常の中断できない方法で進行する必要があり、ロック/ロック解除を使用すると他のスレッドが干渉しないでください。私は正しいですか、それともこのアプローチを避けるべきですか?pthread_sigmask
pthread_mutex_lock