[英]The usage of sig_atomic_t in linux signal mask function
我最近正在學習一本名為《高級Linux編程》的書,並且遇到了這個問題:該書說您應該使用sig_atomic_t
變量類型,以確保如果您在信號處理程序函數中設置了全局標志或計數器,則不會在之間進行上下文切換算術運算(即++
)並將其保存到寄存器中。
我的問題是:如果我們不使用sig_atomic_t
而僅使用另一種類型並且發生上下文切換, sig_atomic_t
發生什么? 我的意思是程序將只返回並保存,例如稍后。 有人可以給我一個方案,它會使我們的代碼不穩定或有故障嗎?
在您描述的場景中運行的風險(從內存讀取到寄存器,更新寄存器,寫入內存,並且在任何這些操作之間發生上下文切換)都是您可能會丟失在其他上下文中所做的更新。
例如:
main context:
read i (=10) from memory to register R1
add 5 to R1
<interrupt. Switch to interrupt context>
read i (=10) from memory to register R1
add 10 to R1
write R1 to i in memory (i = 20)
<end of interrupt. Back to main context>
write R1 to i in memory (i = 15)
如您所見,中斷的更新已丟失。
如果您的類型需要多次操作才能將其寫入內存,而中斷發生在寫操作的中間,則會出現更大的問題。
例如:
main context:
read first half of i (=10) from memory to register R1
read second half of i (=10) from memory to register R2
add 5 to R1/R2 pair
write R1 to first half of i in memory
<interrupt. Switch to interrupt context>
read first half of i (= ??) from memory to register R1
read second half of i (= ??) from memory to register R2
add 10 to R1/R2 pair
write R1 to first half of i in memory
write R2 to second half of i in memory
<end of interrupt. Back to main context>
write R2 to second half of i in memory
在這里,沒有告訴我最終將獲得什么價值。
使用sig_atomic_t
,不會發生第二個問題,因為可以保證類型使用原子讀/寫操作。
這是導致不安全行為的示例:
int64_t a = 2^32-1;
void some_signal_handler()
{
++a;
}
void f()
{
if( a == 0 )
printf("a is zero");
}
假設一個32位架構。 變量a實際上存儲為2個32位整數,並以{0,2 ^ 32-1}開頭。 首先f讀取a的上半部分為0。然后出現信號,執行切換到信號處理程序。 它將a從2 ^ 32-1增加到2 ^ 32 a的新值為{1,0}。 信號處理程序完成,並且f的執行繼續。 f讀取a的下半部分為0。總共f讀取a為零,這從沒打算。
與從信號處理程序寫入變量相比,更好的解決方案是保持管道打開,並從信號處理程序向管道寫入值。 這樣做的好處是它可以喚醒選擇(只要您在管道的讀取端進行選擇),而不會出現任何競爭情況,並使您可以對主信號進行大部分主要處理。選擇循環,您可以在其中隨意使用所需的任何庫函數。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.