2010-10-08 22 views
1

我最近在學習這本書,名爲Advanced Linux Programming,我遇到了這個問題:本書說你應該使用sig_atomic_t變量類型來確保如果你設置一個全局標誌或計數器在信號處理函數中,在算術運算(即++)之間不發生上下文切換並將其保存到寄存器中。sig_atomic_t在linux信號掩碼函數中的用法

我的問題是:如果我們不使用sig_atomic_t,只是用另一種類型和上下文切換時會發生什麼?我的意思是程序會在稍後返回並保存。有人可以給我一個它會使我們的代碼不穩定或錯誤的場景嗎?

+1

您所標記的問題作爲DSP。希望答案只突出顯示DSP上可能出現的問題?這個問題本身並沒有提到DSP。 – 2010-10-08 10:48:13

回答

2

你在你所描述的情況下運行的風險(從內存到寄存器,更新寄存器讀取,寫入內存和任何這些操作之間的上下文切換髮生的)是,你可能會失去在其他方面做了更新。

例如:

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,則不會發生此第二個問題,這是因爲類型是保證使用原子讀/寫操作。

2

下面是其導致不安全行爲的一個示例:

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.然後發生一個信號並執行切換到信號處理程序。它將從2^32-1增加到2^32,新值爲{1,0}。信號處理程序完成並繼續執行f。 f讀取a的下半部分爲0.總而言之,f已經讀取了從零開始的零。

+0

謝謝,在這種情況下,我們需要將所有變量聲明爲原子,我的問題也是關於何時處理另一個信號時發生某些信號。 – 2010-10-08 11:59:48

+0

不客氣。我試圖展示一個最常見的場景。 – 2010-10-08 12:32:55

1

比從信號處理程序中編寫變量一個更好的解決辦法是保持管道開啓和值寫入從信號處理管道。這樣做的好處是,它可以在沒有任何競爭條件的情況下喚醒選擇(只要您在管道的讀取端選擇),並使您可以在主要信號中執行大部分信號處理選擇循環,在那裏你可以自由使用任何你想要的庫函數。