首先,我知道互斥锁通常不被认为是同步安全的。这个问题涉及使用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
无论是。假设没有其他信号(并且我们始终可以阻止任何其他可能有问题的信号),锁定/解锁应始终在当前线程上以正常,不可中断的方式进行,并且使用锁定/解锁应确保其他线程不会干扰。我是对的,还是应该避免这种做法?
如果信号设置为'SA_NODEFER',那么我应该可以在处理程序本身中以相同的方式使用'sigprocmask',不是吗? – nneonneo
另外,由于在两个线程中同时使用'sigprocmask'肯定是一个禁忌,所以进程的sigmask是不可能的。如果有多个信号处理程序,我怀疑处理它的最好方法是阻塞线程sigmask中的所有信号。 – nneonneo
我会重新设计应用程序,如果可以的话,显然,但有很好的理由为什么这样的事情在我的情况下是必要的。 – nneonneo