2014-06-30 84 views
0

我正在嘗試創建簡單的信號處理 - 讓我們來說說像終止這個過程。我有三個獨立的線程在我的程序+主線程中。向所有主題發送信號

問題是,調用該信號會導致當前線程終止,而其他線程仍在運行。

如何將信號發送到其餘線程?如何在發送這些信號時區分這些信號?我不得不在這裏順便使用FIFO。

這裏是我到目前爲止有:

#include <stdio.h> 
#include <stdlib.h> 
#include <sys/stat.h> 
#include <unistd.h> 
#include <linux/stat.h> 
#include <pthread.h> 
#include <string.h> 
#include <signal.h> 

int first[2]; 
int second[2]; 

#define FIFO_FILE "tmp/myfifo" 

void *input(void *ptr) 
{ 
    char str[100], fifo[100]; 
    int length; 
    FILE *fp; 

    while(1) 
    { 
     fp = fopen(FIFO_FILE, "r"); 
     fgets(fifo, 100, fp); 
     if(fifo == "s1") 
     { 
     printf("SIGNAL 1!!!"); 
     exit(1); 
     } 

     printf("Enter the message: "); 
     fflush(stdout); 
     length = read(STDIN_FILENO, str, sizeof(str)); 

     if(str[0] == ';') 
     exit(2); 

     if(length <= 0) 
     { 
     if(length == -1) 
      perror("read"); 
     close(first[1]); 
     exit(2); 
     } 

     if(write(first[1], str, length) != length) 
     { 
     perror("write"); 
     exit(2); 
     } 
    } 
} 

void *countChars(void *ptr) 
{ 
    char str[100], fifo[100]; 
    int length, count = 0; 
    FILE *fp; 

    while(1) 
    { 
     fp = fopen(FIFO_FILE, "r"); 
     fgets(fifo, 100, fp); 
     if(fifo == "s1") 
     { 
     printf("SIGNAL 1!!!"); 
     exit(1); 
     } 

     length = read(first[0], str, sizeof(str)); 
     if(length <= 0) 
     { 
     if(length == -1) 
      perror("read"); 
     close(first[0]); 
     close(second[1]); 
     exit(2); 
     } 
     if(write(STDOUT_FILENO, str, length) != length) 
     { 
     perror("write"); 
     exit(2); 
     } 

     while(str[count] != '\n') count++; 

     write(second[1], &count, sizeof(count)); 

     count = 0; 
    } 
} 

void *output(void *ptr) 
{ 
    int length, count = 0; 
    char fifo[100]; 
    FILE *fp; 

    while(1) 
    { 
     fp = fopen(FIFO_FILE, "r"); 
     fgets(fifo, 100, fp); 
     if(fifo == "s1") 
     { 
     printf("SIGNAL 1!!!"); 
     exit(1); 
     } 

     length = read(second[0], &count, sizeof(count)); 
     if(length < sizeof(count)) 
     { 
     close(second[0]); 
     exit(2); 
     } 

     printf("Number of characters: %d\n", count); 
    } 
} 

void s1_handler(int signo) 
{ 
    FILE *fp; 

    if((fp = fopen(FIFO_FILE, "wb")) == NULL) 
    { 
     perror("fopen"); 
     exit(2); 
    } 

    fputs("s1", fp); 

    fclose(fp); 
} 

int main() 
{ 
    pthread_t t1, t2, t3; 

    if(pipe(first) == -1) 
    { 
     printf("First pipe error"); 
     exit(1); 
    } 

    if(pipe(second) == -1) 
    { 
     printf("Second pipe error"); 
     exit(1); 
    } 

    pthread_create(&t1, NULL, input, NULL); 
    pthread_create(&t2, NULL, countChars, NULL); 
    pthread_create(&t3, NULL, output, NULL); 

    if(signal(SIGINT, s1_handler) == SIG_ERR) 
    { 
     printf("Cant catch SIGINT\n"); 
    } 

    pthread_join(t1, NULL); 
    pthread_join(t2, NULL); 
    pthread_join(t3, NULL); 

    return 0; 
} 

回答

0

只有一個線程接收信號!哪一個?請參閱從報價信息:

http://www.linuxprogrammingblog.com/all-about-linux-signals?page=11

哪個線程接收到信號?

這是最有趣的問題。有兩種情況:

過程控制信號(使用函數kill(2)發送到PID)。 線程有其獨立的信號掩碼,可以使用類似於sigprocmask(2)的pthread_sigmask(2)來操作,所以這樣的信號不會傳遞到阻止該信號的線程。它在這個信號被解除阻塞的過程中被傳送到過程中的一個線程。沒有指定哪個線程會得到它。如果所有線程都阻塞了信號,它將在每個進程隊列中排隊。如果沒有爲信號定義信號處理程序,並且默認操作是終止進程,或者不進行內核轉儲,則整個過程終止。 線程指導信號。有一個特殊的函數來發送信號給特定的線程:pthread_kill(2)。它可以用來從一個線程發送信號到另一個線程(或它本身)。這樣信號將被傳送或排隊等待特定的線程。也有像SIGSEGV一樣由操作系統生成的每線程定向信號。如果沒有信號處理程序爲缺省操作終止進程的信號定義,則線程定向信號終止整個過程。

2

你的程序中有很多(概念性的)錯誤。

信號:標準信號(即SIGINT等非實時信號)未排隊。你的過程只會收到一個,並且(相同類型的)任何其他信號將被丟棄,直到已經交付的信號被以某種方式處理。信號(大部分,無論如何)都作爲一個整體傳遞給整個過程。在沒有你的程序採取其他行動的情況下,信號將被傳遞給進程內的任意線程。您可以可以重新發送一個信號到您的其他線程pthread_kill,但這將需要您使每個線程ID可用於每個其他線程,例如,使用TID的全局表。目前還不清楚你真的想用你的程序來完成什麼,但幾乎可以肯定的是而不是你想做什麼。

FIFOs:您似乎知道使用FIFO在線程之間進行通信是一個可疑的設計,但如果您被告知使用它們,那麼您必須正確使用它們。(1)當FIFO被打開(沒有指定非阻塞模式時),open將被阻塞,直到FIFO的每一端都有讀寫器。這意味着你的所有線程都會阻塞各自的FIFO開放調用,直到你的信號處理程序(見下面的問題)運行並打開FIFO以進行寫入。 (2)即使當你通過打開時,只有一個線程將讀取並消耗信號處理程序編寫的字符串。其他線程將阻止嘗試讀取空的FIFO並且永遠不會處理任何內容。目前,您只需在讀取FIFO的線程中調用exit,該線程將結束程序,但這是您真正想要的嗎?

(3)不需要在每個線程中打開FIFO。您可以在創建線程之前執行此操作,並將FIFO文件描述符傳遞給每個線程或將其設置爲全局。 (4)您每次通過while(1)循環打開(而不是關閉)每個線程中的FIFO。您將很快用完文件描述符。

信號處理程序:您不應該在信號處理程序中使用非異步安全調用。你至少有3 - fopen,fputs,fclose。理想情況下,你想要做一些非常簡單的事情,比如只需設置一個全局開關,在一個信號處理器中,然後離開。所以,如果這不僅僅是腦死亡課堂任務,你應該完全重新思考。

我會建議您準確闡述您的目標是什麼程序,您可以得到一些建議如何達到它。