實作 Signal.trap
回呼的注意事項¶ ↑
與在 C 或大多數其他語言中實作訊號處理常式一樣,傳遞給 Signal.trap
的所有程式碼都必須是可重入的。如果您不熟悉可重入性,您需要在閱讀本文檔的其餘部分之前在 Wikipedia 或其他地方閱讀有關它的內容。
最重要的是,“執行緒安全性”不能保證可重入性;而通常用於執行緒安全性的方法,例如 Mutex#lock 和 Mutex#synchronize,甚至會阻止可重入性。
Ruby VM 實作的細節¶ ↑
Ruby VM 會延後執行 Signal.trap
回呼,直到其內部資料結構安全為止,但它不知道您的程式碼中資料結構何時安全。Ruby 透過註冊僅使用 非同步訊號安全函式 的簡短 C 函式,來實作延後訊號處理,作為訊號處理常式。這些簡短的 C 函式只會執行足夠的動作,告訴 VM 在 Ruby Thread
主程式稍後執行透過 Signal.trap
註冊的回呼。
在 Signal.trap
區塊中呼叫不安全的函式¶ ↑
有疑問時,請將以下未列為安全的任何內容視為不安全。
-
Mutex#lock、Mutex#synchronize 和使用它們的任何程式碼明確不安全。這包括標準函式庫中的
Monitor
,它使用 Mutex 來提供可重入性。 -
Dir.chdir
搭配區塊 -
當
IO#sync
為 false 時,任何IO
寫入操作;包括IO#write
、IO#write_nonblock
、IO#puts
。預設管道和 socket 的「IO#sync = true」,因此除非已停用IO#sync
,否則寫入它們是安全的。 -
File#flock
,因為底層的 flock(2) 呼叫未由 POSIX 指定
Signal.trap
區塊內常見的安全操作¶ ↑
-
指派和擷取區域、執行個體和類別變數
-
不執行區塊的常見
Array
、Hash
、String
、Struct
操作通常是安全的;但如果在其他地方進行反覆運算,請小心。 -
Thread::Queue#push
和Thread::SizedQueue#push
(自 Ruby 2.1 起) -
透過
Thread.new
/Thread.start 建立新的Thread
可用於解決訊號處理常式內無法使用 Mutex 的問題 -
在傳遞給
Signal.trap
的區塊內使用Signal.trap
是安全的 -
在
Integer
和Float
上的算術運算(「+」、「-」、「%」、「*」、「/」)此外,信號處理常式不會在兩個連續的區域變數存取之間執行,因此當在信號處理常式中使用
Integer
和Float
類別時,例如「+=」和「-=」的捷徑不會觸發資料競爭。
在 Signal.trap
內部安全的系統呼叫包裝器方法¶ ↑
由於 Ruby 在許多 非同步信號安全 C 函式 周圍有包裝器,因此許多 IO
、File
、Dir
和 Socket
方法的對應包裝器是安全的。
(不完整的清單)
-
Dir.chdir
(沒有區塊引數)
…