非同步訊號安全和執行緒安全

2021-06-18 05:33:53 字數 1600 閱讀 8594

2011-12-24 20:10:54

|  分類:

linux|字型大小

訂閱 問題源自於apue中stevens老先生有關執行緒安全函式的介紹,stevens有曰:如果乙個函式對於多執行緒來說是重入的,則說這個函式是執行緒安全的,但這並不能說明對訊號處理程式來說也是重入的。也就是說訊號安全重入函式要求要比執行緒安全更加嚴格。但是,我想知道為什麼,為什麼執行緒都可以重入了,而在訊號卻不行?

猜想:諸如printf之類的標準庫函式內部實現可能有個互斥鎖,這個互斥鎖是專門針對於io緩衝區的,也就是說每個邏輯執行流要列印前(列印意味著要向緩衝區寫入字元)都要獲得鎖,然後把要列印的內容輸入緩衝區,最後釋放互斥鎖。

解釋:由於要在列印前獲取互斥鎖,所以在訊號處理程式中呼叫printf可能要出現死鎖:當前邏輯執行流呼叫printf,正好取得鎖時,訊號發生了,此時執行流不得不呼叫訊號處理函式,正巧訊號處理函式也要執行列印printf,同樣要獲取緩衝區控制鎖,但是鎖已經被自己先前lock了(這正是自己二次加鎖死鎖現象),所以出現了死鎖。同樣這個也可以很好的解釋為什麼執行緒呼叫printf不會死鎖,因為即使如果乙個執行緒正加好鎖發生執行緒切換,新來的執行緒要執行printf,但是發現緩衝區已鎖,自己睡眠等待即可,不會出現死鎖,到先前那個執行緒執行完列印後,自然會釋放鎖的。

證明:我們的以上猜想核心就是基於標準緩衝區含有互斥鎖,每次printf等函式操作緩衝區都要加鎖,所以我們只需要證明這個鎖存在就行了。大家直接可以去看標準庫**,但是我寫一段程式可以近似地來佐證這個想法。

多執行緒情況:這裡我們開闢乙個執行緒,然後主線程和副執行緒都同時用printf向螢幕列印乙個字串,然後我們可以檢視,如果字串是每次都完整列印,那說明很可能是因為有鎖保證每次列印完整,不會因為執行緒排程而出現字串中斷情況。

void*thread_main(void*arg)  

returnnull;  

}intthread_new(void* (*fn)(void*),void*arg)  

if(pthread_create(&tid, &attr, fn, arg) != 0)  

pthread_attr_destroy(&attr);  

return(0);  

}intmain()  

return(0);  

}   

訊號情況:這裡設定乙個每隔10毫秒就列印一次的訊號處理函式,大家可以執行看,執行久點,最後必然會出現死鎖,也就是螢幕不再列印字元了,同時我們可以觀察下每次死鎖都發生在主函式列印時,因為此時訊號切換發生死鎖。

voidgotsig(intn)  

voidsig_safe(void)  

}  

執行緒安全 可重入和非同步訊號安全

在編寫伺服器軟體時,為了提高程式的穩定性,需要考慮執行緒安全 可重入和訊號安全。當多執行緒軟體執行時,作業系統隨時可能暫停乙個執行緒的執行,將cpu分配給另外乙個執行緒。考慮下面的執行流程。假設執行緒1和執行緒2被排程到同乙個cpu上執行,它們分別執行int to str 10 和int to st...

訊號可重入執行緒安全

訊號可重入執行緒安全 2009 08 28 16 54 之所以把這幾個概念放一起,是因為它們組合在一起容易出現一些莫名其妙的錯誤,而且一旦出現,還很難被發現。更糟糕的是它們的出現需要一定的時間,並不是非常容易重現的,而且需要了解的比較多才能更好的理解它們發生的原因。這裡要用例子闡述一下。訊號的是un...

Java執行緒安全和非執行緒安全

arraylist是非執行緒安全的,vector是執行緒安全的 hashmap是非執行緒安全的,hashtable是執行緒安全的 stringbuilder是非執行緒安全的,stringbuffer是執行緒安全的 什麼是執行緒安全?執行緒安全和非執行緒安全有什麼區別?分別在什麼情況下使用?非執行緒安...