2010-10-15 133 views
1

我正在尋找關於重入的一些信息,然後我遇到了關於信號和線程的信息。兩者有什麼區別?信號與線程

請指教。

非常感謝。

回答

4

您正在比較蘋果和橘子。 Signal Programming是事件驅動編程,可用於影響線程。然而,信號編程範例可以用於單線程應用程序。

+0

@sasayins:這是本書的開始,你正在考慮* nix。 – yadab 2010-10-15 11:16:57

1

要理解信號,最好從思考單線程程序開始。這個程序正在對它的一個線程做任何事情,然後將信號傳遞給它。如果程序爲該信號註冊了一個信號處理程序(一個調用函數),那麼在調用信號處理程序函數時,該程序的正常執行將暫停一點點(非常類似於硬件中斷會中斷操作系統運行中斷服務程序)並運行程序已經註冊的功能來處理該信號。因此,與代碼:

#include <stdio.h> 
#include <signal.h> 
#include <unistd.h> // for alarm 

volatile int x = 0; 

void foo(int sig_num) { 
    x = sig_num; 
} 

int main(void) { 
    unsigned long long count = 0; 
    signal(SIGALRM, foo); 
    alarm(1); // This is a posix function and may not be in all hosted 
       // C implementations. 
       // SIGALRM will be sent to this process in 1 second. 
    while (!x) { 
     printf("not x\n"); 
     count++; 
    } 
    printf("x is %i and count = %llu\n", x, count); 
} 

該程序將循環,直到有人給它發送一個信號(這種情況如何可能會因平臺而有所不同)。如果發送信號SIGINT,則foo將設置爲x並且循環將退出。確切地說foo被調用的循環中的位置並不清楚。它可能發生在打印和遞增計數之間,恰好在條件被測試之後,在打印期間......很多地方,真的。這就是爲什麼信號可能帶來併發或重入問題 - 它們可以在事先沒有其他代碼知道它發生的情況下改變它們。

x被聲明爲volatile的原因是沒有那麼多編譯器可能會認爲「嘿,沒有人在主要更改x和main不會調用任何其他函數,所以x永遠不會更改」並優化循環測試。指定volatile告訴C編譯器,這個變量可以被看不見的力(例如信號處理程序,其他線程,或者有時甚至是內存映射設備控制寄存器的硬件)改變。

這是很容易,以確保x被看出來妥善兩個信號處理程序和主代碼執行之間因爲x就是一個整數(加載和存儲它很可能是一個指示組件中的每個),這是隻是在這種情況下被的東西(信號處理程序,而不是主代碼)所改變,並且它僅被用作簡單的布爾值。如果x是某種其他類型(如字符串),則由於信號可能隨時中斷您的信號處理程序可能會覆蓋部分字符串,而主代碼正在讀取字符串。當你在刷牙時,有人會凍結時間,用眼鏡蛇取代你的牙刷,然後解凍時間,這可能會有結果。

有關信號的更多信息 - 它們是C語言的一部分,但它們的大部分用途並未被C覆蓋。許多與信號有關的Linux,Unix和POSIX函數都不是是C語言的一部分,但很難拿出合理的(和小的)信號使用的例子,它不依賴於C標準以外的東西,這就是我使用alarm函數的原因。作爲C的一部分的raise函數可以用來向自己發送信號,但是要示例更難。

當信號看起來像現在一樣可怕時,大多數系統都有更多的功能,使它們更容易使用。

線程,最後

線程同時執行,而信號中斷。雖然有一些線程庫實際上以這種方式實現線程,但事實並非如此,最好是用這種方式來思考線程。由於計算機程序的能力實際上非常有限,因此它們能夠看到線程可以像對待信號處理程序一樣阻礙主執行代碼(可能比信號處理程序更頻繁)。

想象一下,你即將再次刷牙,但這次你是清醒和盲目的。現在你的室友,也是高清和盲人,進來用一些硅膠封口劑固定水槽。就像你拿到牙膏一樣,他把硅膠管放在牙膏管的頂部,然後你拿起硅膠管而不是牙膏。請記住,既然你既是盲人又是高級(並且不會碰到對方),你們都假設沒有其他人在使用水槽,所以你永遠不會意識到你剛把牙刷上的硅膠放在你的牙刷上,要意識到他正在試圖用牙膏填滿瓷磚和水槽背面之間的裂縫。

幸運的是,有線程可以互相溝通,以便某些東西當前正在使用,所以其他線程應該遠離(比如在刷牙時鎖定門)。