2014-06-30 53 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。理想情况下,你想要做一些非常简单的事情,比如只需设置一个全局开关,在一个信号处理器中,然后离开。所以,如果这不仅仅是脑死亡课堂任务,你应该完全重新思考。

我会建议您准确阐述您的目标是什么程序,您可以得到一些建议如何达到它。