首先,我知道互斥锁通常不被认为是异步安全的。这个问题涉及在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
or 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);
}
逻辑如下: inside被阻塞sigfoo_handler
,SIGFOO
因此它不能中断pthread_mutex_lock
。在-protected 关键区域期间update_gvars
,SIGFOO
不能在当前线程中引发within ,pthread_sigmask
因此它也不能中断pthread_mutex_lock
。假设没有其他信号(并且我们总是可以阻止任何其他可能有问题的信号),锁定/解锁应该始终在当前线程上以正常、不间断的方式进行,并且使用锁定/解锁应该确保其他线程不会不要干涉。我是对的,还是应该避免这种方法?