簡體   English   中英

sig_atomic_t在Linux信號掩碼功能中的用法

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM