首先,我知道互斥鎖通常不被認爲是同步安全的。這個問題涉及使用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