2010-10-20 60 views
0

我正在將多線程應用程序從HP-UX遷移到Solaris,到目前爲止,除了一件事外,一切都可以!應用程序有一個處理信號的線程,當它們中的一些被接收時,它會運行一些清理(記錄,殺死子進程等)。POSIX線程在HP-UX和Solaris 10之間的行爲不同

我已經減少了代碼一樣,因爲它有可能使一個莫名其妙簡單的例子顯示了問題:使用的編譯命令行

#include <pthread.h> 
#include <stdlib.h> 
#include <stdio.h> 
#include <string.h> 
#include <unistd.h> 
#include <signal.h> 
#include <synch.h> 
#include <iostream> 
#include <unistd.h> 

using namespace std; 

pthread_t  m_signalHandlerThread; 
sigset_t  m_signalSet; 

void signalHandler() 
{ 
    while (true) 
    { 
     cout << "SigWait..." << endl; 
     sigwait(&m_signalSet, &sig); 
     cout << "Signal!! : " << sig << endl; 

     break; 
    } 

    cout << "OUT" << endl; 
} 

void* signalHandlerThreadFunction(void* arg) 
{ 
    signalHandler(); 

    return (void*)0; 
} 


int main() 
{ 
    sigemptyset(&m_signalSet); 
    sigaddset(&m_signalSet, SIGQUIT);    //kill -QUIT 
    sigaddset(&m_signalSet, SIGTERM);    //kill 
    sigaddset(&m_signalSet, SIGINT);    //ctrl-C 
    sigaddset(&m_signalSet, SIGHUP);    //reload config 

    if (pthread_create(&m_signalHandlerThread, NULL, signalHandlerThreadFunction, NULL)) 
    { 
     cout << "cannot create signal handler thread, system shut down.\n" << endl; 
    } 

    int iTimeout = 0; 
    while (1) 
    { 
     if (iTimeout >= 10) 
      break; 

     sleep(1); 
     iTimeout++; 
     cout << "Waiting... " << iTimeout << endl; 
    } 

    cout << "END" << endl; 

    exit (0); 
} 

: 的Solaris:

CC -m64 -g temp.cpp -D_POSIX_PTHREAD_SEMANTICS -lpthread 

HP- UX:

/opt/aCC/bin/aCC +p +DA2.0W -AA -g -z -lpthread -mt -I/usr/include temp.cpp  

運行這兩個應用程序的行爲(按下摹CTRL + C,而在10秒循環):

HP-UX:

./a.out 

SigWait... 
Waiting... 1 
Waiting... 2 
Signal!! : 2 <---- CTRL + C 
OUT 
Waiting... 3 
Waiting... 4 <---- CTRL + C again to terminate 

的Solaris:

./a.out 

SigWait... 
Waiting... 1 
Waiting... 2 <---- CTRL + C 
^C 

任何幫助將更加然後受歡迎的,因爲我已經撕裂我的頭髮(沒有太多):)!

謝謝!

回答

-1

這是處理信號的非正統方法。如果你想結婚的信號和線程,更好的選擇將是從信號從內部串行到通常的signal handlers到另一個線程,負責實際處理事件。

這也是一個更好的選擇,因爲它是未定義MT應用程序中的哪個線程接收信號。沒有信號阻塞的任何線程可能會收到它。如果你有2個線程(在這個例子中你有兩個線程),那麼任何線程都可能得到SIGINT。

您可能想要檢查sigprocmask()作爲告訴操作系統SIGINT應該被阻塞在線程中的一種方式。這應該爲每個線程完成,IIRC甚至是調用sigwait()的那個線程。


Edit1。其實我錯了上面的「應該爲每個線程完成」一點。一個新線程從當前線程繼承其信號掩碼。我意識到這不可能是真的,因爲這會引入競爭條件:信號到達創建新線程但尚未設置其信號掩碼的時間。換句話說,在主線程中設置信號屏蔽就足夠了。

+0

謝謝!這確實解決了我的問題,即使在整個應用程序中。 我只是不明白爲什麼這可以在HP-UX上運行......也許在該線程實現中,所有線程都會收到信號? – JoaoSantos 2010-10-20 13:58:13

+0

「也許在該線程實現所有線程接收信號?」應用程序收到信號 - 但它可以在任何* random *線程中處理。 HP-UX可能已經注意到,您的應用程序中的一個線程使用sigwait(),而Solaris尚未引起麻煩。信號與線程最好被描述爲一個灰色區域,你不想實驗。即使POSIX也不能完整地描述這些行爲,因爲細節差別很大,因爲一個操作系統對另一個操作系統有很大不同 – Dummy00001 2010-10-20 14:14:57

+0

我給這個答案-1。這個答案是錯誤的,因爲你不能將信號從傳統的信號處理程序序列化到任何其他線程或數據結構。你將不得不在信號處理程序中使用一些鎖定,這是不可能的。在信號處理程序中你可以做的很少,使用鎖定原語不是其中之一。 – wilx 2010-10-20 16:09:58

4

未指定您的2個線程中的哪一個將處理SIGINT。如果您只需要其中一個線程來處理信號,則需要在所有其他線程中阻止該信號。

+0

您的回答指出我正確的方向。謝謝。 – JoaoSantos 2010-10-20 14:13:55

1

您應該使用pthread_sigmask來阻止其他線程的信號。該頁面還包含具有信號處理線程的程序示例。

+0

您對使用的功能是正確的。我接受了之前的版本,因爲它在你之前發佈,儘管它提到了單線程函數的調用。 – JoaoSantos 2010-10-20 14:00:02

+0

@JoaoSantos:''pthread_sigmask()'相當於'sigprocmask()'。沒有「單線程」或「多線程」信號功能 - 有一些功能在MT應用程序中定義了行爲(如兩個)或未定義(例如,'sigpause()'只能用於ST應用程序/ shouldn根本不會被使用)。 – Dummy00001 2010-10-20 14:20:46

1

關於如何處理信號以及在多線程應用程序的唯一途徑是做到以下幾點:

  1. 阻止所有在main()早期信號,其他線程都在催生之前,使用pthread_sigmask()
  2. 產生一個信號處理線程。使用sigwait()sigwaitinfo()來處理簡單循環中的信號。

這種方式除了專門用於信號處理的線程將不會獲得信號。而且,由於信號傳輸是以這種方式同步的,因此您可以使用您擁有的任何線程間通信功能,這與傳統信號處理程序內部不同。