訊號可重入執行緒安全
2009-08-28 16:54
之所以把這幾個概念放一起,是因為它們組合在一起容易出現一些莫名其妙的錯誤,而且一旦出現,還很難被發現。更糟糕的是它們的出現需要一定的時間,並不是非常容易重現的,而且需要了解的比較多才能更好的理解它們發生的原因。
這裡要用例子闡述一下。
訊號的是unix系統上是最原始的程序間通訊方式之一(參考<
#include
#include
<
signal
.h>
#include
#include
time
.h>
void gotsig(
int n)
int main()}
這個**的意思就是每一毫秒傳送給自己一次sigalrm訊號,然後一直列印
這個**有什麼問題,咋一看,看不出來有什麼問題吧(如果你一眼就看出問題來,那麼不要再往下閱讀了^^)
答案是,很可能會死鎖,死鎖有幾個必要條件,我要得到資源a的時候被阻塞,而能釋放a的那個傢伙又在等待我已經擁有的資源。
那麼這裡資源在哪呢,在printf的鎖裡,是什麼東西,我咋不知道呢??
眾所周知,作業系統支援多執行緒,而且標準io是有緩衝的,顯然stdout是全域性資源(檔案是屬於程序的資源,是所有執行緒共享的,就像位址空間一樣). 那麼多執行緒printf的時候會發生什麼?很顯然,緩衝區的概念(消費者和生產者的故事應該知道)出來了,必須得有鎖,否則緩衝區可能會出問題的(乙個列印aaa,乙個列印bbb,最後有可能列印aabbba)
這樣的鎖如果有,就表明printf是執行緒安全的,否則就不是執行緒安全的!
顯然如果標準庫的printf一族如果不是執行緒安全的,那麼執行緒中就得自己加鎖了,多麻煩的事情(雖然c標準沒有執行緒的概念,但是我的標準庫是執行緒安全的);
這樣printf的行為大概為
int printf(const char *fmt,...)
這個鎖肯定是所有執行緒可見的,這個函式不可重入,在訊號處理中呼叫的時候,被中斷的地方可能正是加鎖和解鎖之間的位置,這樣訊號處理中的printf進行同樣的加鎖解鎖過程,因為那時候它已經擁有了鎖(在被打斷的時候),再去要鎖,那麼肯定得不到,訊號處理中的printf永遠阻塞在那鎖的獲取**上,永遠不會返回,訊號處理函式也就永遠不會返回,顯然死鎖了
strace ./a.out 會發現阻塞在futex上,這個系統呼叫正是我的系統上鎖的實現所使用的(pthread_mutex_lock)
目前的死鎖還只是這個執行緒,當別的執行緒呼叫printf時,也死鎖了
總結一下
訊號處理中不能呼叫不可重入函式,帶有鎖的函式是不可重入的
printf是執行緒安全的,同理,malloc也是,只是malloc操作位址空間,printf操作檔案而已,都是全域性資源,都有鎖的
這只是個我遇到的情況,詳細可以參考apue
執行緒安全 可重入和非同步訊號安全
在編寫伺服器軟體時,為了提高程式的穩定性,需要考慮執行緒安全 可重入和訊號安全。當多執行緒軟體執行時,作業系統隨時可能暫停乙個執行緒的執行,將cpu分配給另外乙個執行緒。考慮下面的執行流程。假設執行緒1和執行緒2被排程到同乙個cpu上執行,它們分別執行int to str 10 和int to st...
可重入 執行緒安全
可重入 乙個函式可以同時被呼叫,不會有影響 執行緒安全 乙個函式可以被多執行緒同時呼叫,不會有影響.可重入 執行緒安全,需要比執行緒安全更強的條件.乙個函式是可重入的,一定是執行緒安全的 乙個函式是執行緒安全的,不一定是可重入的 比如 malloc不是非同步 訊號安全,但是執行緒安全的,因此其不是可...
執行緒安全 可重入
昨天有人問可重入和執行緒安全,實際是混在一起淘漿糊了 這2個是完全不同的概念 可重入函式只有在signal下會發生,比如乙個函式在執行時被中斷,在中斷處理函式中又一次被呼叫,這2次 每次 呼叫都能產生正確的結果,那就個可重入函式 看乙個不可重入的例子 void sig handler int sig...