2011-02-05 94 views
6

我正在處理一個使用信號在兩個進程之間傳輸二進制消息的任務,目的是瞭解信號(這確實是一個奇怪的用途)。爲什麼我的信號處理程序不被調用?

在我的程序中,兩個進程傳遞一個代碼,然後一個消息傳遞給另一個。 SIGUSR1表示0,SIGUSR2表示1.思路是發送消息的進程將使用kill函數與SIGUSR中的任何一個來獲取消息,接收進程將有一個信號處理程序來解釋代碼。

所以這裏是問題所在。 我有發件人啓動。它在等待代碼被髮送時睡覺。 收件人發送兩個SIGINT來表示「密碼」,使用pidof(8)找到發件人的pid。

一旦發送者的信號處理程序已經讀取這些信號,就認爲它是正確的密碼,然後繼續發送消息。

接收器現在已經經歷了幾個函數,並且每秒鐘都在睡覺,等待每個位通過中斷傳遞。問題是,這從來沒有發生過。

我已經設置它,使得發送者發送一個比特(0在這種情況下),如下所示:

kill(SIGUSR1,washingtonPID); 

其中washingtonPID是接收器的PID,以及我已驗證這是正確的PID。

接收器的處理程序掛接像這樣:

//IN MAIN 
    signal(SIGINT,bitReceiver); 
    signal(SIGUSR1,bitReceiver); 
    signal(SIGUSR2,bitReceiver); 
//OUTSIDE MAIN 

    void bitReceiver(int signum) 
{ 
    if(signum == SIGUSR1) 
    { 
     fprintf(stderr,"SIGUSR1 - 0"); 
     bit = 0; 
    } 
    else if (signum == SIGUSR2) 
    { 
     fprintf(stderr,"SIGUSR2 - 1"); 
     bit = 1; 
    } 
    else //sigint 
    raise(SIGINT); 

    return; 
} 

,其中一位是一個全局變量。它最初設置爲-1。

這裏是一個讀取位功能:

int receiveBit() 
{ 
    while(bit == -1) 
    { 
     sleep(1); 
    } 
    fprintf(stderr,"%d",bit); 
    int bit2 = bit; 
    bit = -1; 
    return bit2; 
} 

所以基本運行經過是這樣的: 代碼已經從接收到發送方發送後,發送者開始發送的終止信號USR1和USR2到接收器,最終應該形成一個二進制消息。

接收器正在等待此刻,每秒鐘都在睡覺。當它被中斷時,處理程序會將該位設置爲0或1,將其踢出睡眠狀態,打印位並返回。

,如果我讓這兩個程序運行正常,在reciever只是坐在睡眠和處理程序不會被調用(即使我可以看到調用由其他工藝製成。

如果我阻止發件人,然後手動發送Kill信號,我可以發送一個,也許兩個信號,兩者都可以正確處理,之後任何一個信息都會打印到終端上,如'用戶信號2',這不是我的程序,程序立即停止

任何有關爲什麼我的處理程序沒有被煽動的理解,以及爲什麼我不能手動發送更多的一個或兩個信號,將不勝感激

感謝您的時間。

編輯: 看起來好像人們難住這一點。有沒有我可以嘗試的調試技巧?

+0

我可以告訴你的是,這是一個可笑的效率低下的設計,並且使用`pidof`來查找一個過程並不安全或不健全。 (想象一下,爲了竊取密碼,某個人使用相同的名稱創建了一個進程。)您應該使用UNIX域套接字進行這種類型的通信。 – 2011-02-05 16:47:56

+3

如果您在第一段中會注意到,我提到這是一項任務而不是現實世界的問題。這是低效的,並且使用pidof是不安全的。但我並不擔心這一點。 – Blackbinary 2011-02-05 16:54:14

+1

「bit」聲明爲「volatile」嗎? – 2011-02-05 16:58:06

回答

5

正如很多人已經評論過的,你不應該用信號做這件事。當它出現錯誤(並且會像它那樣)試圖找出未定義行爲背後的錯誤時,即使不是不可能,也很難。

因爲fprintf在同一個流上運行,所以在信號處理程序內部使用非類似fprintf的異步安全系統調用可能會破壞數據。與共享變量相同。

由於您使用的是linux,相同類型的信號不會被阻塞,這意味着相同信號的快速傳遞可能會導致對處理程序的遞歸調用。一旦捕獲到信號,信號的處置就會重置爲SIG_DFL,並且需要再次在處理程序中重新建立(如果在重新建立更改之前傳遞信號,也可能會失敗)。

這就是爲什麼您可以在信號重置爲默認值之前發送最多1個相同類型的信號,並通過「用戶信號xx」終止程序。

我會建議你停止折磨自己的代碼,並抓取一些教科書或教程,並嘗試遵循。

信號調用也應該避免。從手冊頁:

信號的行爲()跨 UNIX版本的不同而不同,也有所不同 歷史跨越不同版本的Linux 。 避免使用:改爲使用 sigaction(2)。

0

我注意到了幾件事情。

  • 信號處理程序中使用的任何共享變量都應設置爲volatile
  • fprintf()不是一個用於信號處理程序的安全函數。檢查您的手冊頁signal()以獲取安全功能的列表。
  • 另外,如果信號處理程序在觸發後重置回SIG_DFL,則signal()具有幾個不同的實現。大多數Unix用戶建議使用sigaction()來確保你得到你想要的行爲。或者爲了測試你可以重置處理程序本身的信號處理程序,看看是否會給你一個不同的行爲。
相關問題