2014-12-06 111 views
0

我正在創建一個多線程應用程序,該應用程序永遠運行,直到用戶發送中斷(即CTRL + C),其中運行output_report()方法。下面是代碼的樣本:pthread條件不被滿足

void output_report(int signo) { 
    printf("Exiting!\n"); 

    pthread_mutex_lock(&mutex_num_of_threads); 
    programClosing = true; 
    while (numOfThreads != 0){ 
     pthread_cond_wait(&allThreadsCompleteCond, &mutex_num_of_threads); 
    } 
    pthread_mutex_unlock(&mutex_num_of_threads); 

    printf("Closing Now!\n"); //This part is not reached 

    pthread_exit(NULL); // Is this needed? 
    exit(0); 
} 

void dispatch(struct pcap_pkthdr *header, const unsigned char *packet, 
     int verbose) { 

    static bool thread_settings_initialised = false; 

    //Only run the first time dispatch method runs 
    if (thread_settings_initialised == false){ 
     thread_settings_initialised = true; 

     if (signal(SIGINT, output_report) == SIG_ERR) 
      fprintf(stderr, "\ncan't catch SIGINT\n"); 

     //...  

     //Set mutex for the appropriate variables to remain thread safe 
     pthread_mutex_init(&mutex_num_of_threads, NULL); 
     //... 

     //Set attr so threads are "Detached" 
     pthread_attr_init(&attr); 
     pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); 

     //Set pthread_cond_init 
     pthread_cond_init(&allThreadsCompleteCond, NULL); 
    } 

    //... 

    pthread_mutex_lock(&mutex_num_of_threads); 
    numOfThreads++; 
    pthread_mutex_unlock(&mutex_num_of_threads); 


    //... 
    int rc = pthread_create(&tid, &attr, analyse, (void *) &data); 
    //... 
} 

void analyse(void *thread_data) { 
    //... 

    pthread_mutex_lock(&mutex_num_of_threads); 
    numOfThreads--; 
    if (programClosing == true && numOfThreads == 0) { 
     pthread_cond_signal(&allThreadsCompleteCond); 
    } 
    pthread_mutex_unlock(&mutex_num_of_threads); 

    pthread_exit(NULL); 
} 

我的問題是,當過我使用CTRL + C,該方案只是有點暫停(不是完全退出,因爲程序仍在運行,我必須使用CTRL。 + z擺脫它)。該程序輸出「退出」,但不是「現在關閉」意味着「allThreadsCompleteCond」沒有被滿足,但我不知道爲什麼。

UPDATE

感謝Paul Griffiths的答案,我更新了我的代碼如下所示:

void exitHandler(int signum){ 
    programClosing = 1; 
} 

void output_report(int signo) { 
    while (programClosing == 1){ 
     printf("Exiting!\n"); 
     //rest same as before 
     exit(0) 
    } 
} 

void dispatch(struct pcap_pkthdr *header, const unsigned char *packet, 
     int verbose) { 

    static bool thread_settings_initialised = false; 
    int rc; 

    printf("DISPATCH!\n"); 
    //Only run the first time dispatch method runs 
    if (thread_settings_initialised == false){ 
     thread_settings_initialised = true; 

     //Set mutex for the appropriate variables to remain thread safe 
     //.. 

     //Set attr so threads are "Detached" 
     //.. 

     //... 

     if (signal(SIGINT, exitHandler) == SIG_ERR) 
      fprintf(stderr, "\ncan't catch SIGINT\n"); 

     pthread_t exit_tid; 
     rc = pthread_create(&exit_tid, &attr, output_report, (void *) NULL); 
     if (rc) { 
      printf("ERROR; return code from pthread_create() is %d\n", rc); 
      exit(-1); 
     } 

    } 

    //... 
    ///same as before 

} 

現在更新的代碼仍然甚至不輸出文本 「退出」!

+1

'的printf()','pthread_mutex_lock()的','調用pthread_cond_wait()'和'調用pthread_mutex_unlock()'是不是安全,從信號處理程序調用。你所看到的行爲就是這方面的證據。你需要重新思考你的策略。 – 2014-12-06 01:33:54

+0

最新的替代方案 – 2014-12-06 01:34:19

+1

很可能讓信號處理程序不做任何事情,而是設置一個類型爲'sig_atomic_t'的狀態變量,並且讓單個線程定期檢查它,並在其他線程關閉時關閉其他線程。一般來說,混合線程和信號會導致很多類似的問題。 – 2014-12-06 01:38:50

回答

1

printf(),並且特別地,在這裏,pthread_mutex_lock(),pthread_cond_wait()pthread_mutex_unlock()對於從信號處理器調用通常是不安全的。你所看到的行爲就是這方面的證據。有時候可以這樣做,但實現這一目標需要確保程序的其餘部分不會因此受到不利影響,這對於非平凡程序通常是不可行的。

信號處理開始時可能非常棘手,一般而言,混合線程和信號使事情變得更加棘手。一般的方法是(1)只調用信號處理程序中異步信號安全的函數(你可以找到它們的列表here);和(2)儘可能少地在信號處理器中工作。此外,您經常需要考慮(3)阻止信號的傳遞或關鍵部分的一些信號,因爲您不希望一組操作可能不利地干擾這些操作的信號而中斷一組操作。

volatile sig_atomic_t類型的變量可以通過信號處理程序安全地寫入,所以一個常見的策略是讓您的信號處理程序不做任何事情,而是設置一個變量,然後您的主程序會定期檢查該變量。例如:

volatile sig_atomic_t im_done = 0; 

void handler(int signum) 
{ 
    im_done = 1; 
} 

int main(void) 
{ 
    /* Do init stuff and register your signal handler */ 

    while (!im_done) { 

     /* Do your main work here */ 

    } 

    /* Clean up and get ready to exit here */ 

    return 0; 
} 
+0

你的新代碼似乎並沒有在任何地方調用'output_report()',所以顯然你永遠不會看到'printf(「Exiting!\ n」)的效果;''output_report()'本身看起來仍然是寫入的成爲一個信號處理程序,這不是你想要的。 – 2014-12-06 02:43:27

+0

對不起,我寫錯了,但結果相同。它仍然沒有工作!\t \t printf(「退出!\ n」);不敢跑! – 2014-12-06 03:15:35

+0

好的,你需要坐下來思考它,基本上設計並調試你的程序。在這裏發佈一些小片段,並說它不起作用不會使它開始工作。 – 2014-12-06 03:17:20