向所有线程发送信号

时间:2014-06-30 09:37:00

标签: c linux multithreading posix

我正在尝试创建简单的信号处理 - 让我们说像终止这个过程。我的程序+主线程中有三个单独的线程。

问题是调用信号会导致当前线程终止,而其他线程仍在运行。

如何将信号发送到剩余的线程?如何在发送这些信号时区分这些信号?

顺便说一句,我必须使用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;
}

2 个答案:

答案 0 :(得分:2)

你的程序中有很多(概念上的)错误。

信号:标准信号(即SIGINT等非实时信号)未排队。您的进程将只收到一个,并且任何其他信号(相同类型)将被丢弃,直到已经交付的信号以某种方式处理。信号(大多数情况下,无论如何)都作为一个整体传递给整个过程。如果您的程序没有采取其他措施,信号将被传递到流程中的任意线程。您可以重新发送您使用pthread_kill捕获到其他线程的信号,但这需要您通过使用全局TID表使每个其他线程都可以使用每个线程ID 。目前还不清楚你真正想要用你的程序完成什么,但几乎可以肯定你想做什么。

FIFO:您似乎知道使用FIFO在线程之间进行通信是一种可疑的设计,但如果您被告知要使用它们,那么您必须正确使用它们。

(1)当FIFO被打开(没有指定非阻塞模式)时,open将被阻塞,直到FIFO的每一端都有一个读写器和一个写入器。这意味着你的所有3个线程都将阻塞它们各自的FIFO开放调用,直到你的信号处理程序 - 看下面的问题 - 运行并打开FIFO进行写入。

(2)即使你超过了打开,只有一个线程会读取并使用信号处理程序编写的字符串。其他线程将阻塞尝试读取空FIFO并且永远不会处理任何事情。目前你只是在读取FIFO的线程中调用exit,这将结束程序,但这是你真正想要的吗?

(3)无需在每个线程中打开FIFO。您可以在创建线程之前执行此操作,并将FIFO文件描述符传递给每个线程或仅将其设置为全局。

(4)每次通过while(1)循环打开(而不是关闭)每个线程中的FIFO。你会很快用完文件描述符。

信号处理程序:您不应在信号处理程序中使用非异步安全调用。你有至少3 - fopen,fputs,fclose。理想情况下,您希望在信号处理程序中执行非常简单的操作,例如设置全局开关,然后退出。因此,如果这不仅仅是脑死亡课程,你应该重新考虑这一点。

我建议你详细说明你的目标是什么,你可以得到一些如何达到它的建议。

答案 1 :(得分:0)

只有一个线程收到信号!哪一个?请参阅以下引用的详细信息:

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

  

哪个线程收到信号?

     

这是最有趣的问题。有两种情况:

     

过程导向信号(使用kill(2)等函数发送到PID)。   线程有其独立的信号掩码,可以使用类似于sigprocmask(2)的pthread_sigmask(2)进行操作,因此这种信号不会传递给阻塞此信号的线程。在此信号未被阻止的情况下,它被传送到进程中的一个线程。没有指定哪个线程会得到它。如果所有线程都阻塞了信号,则它将在每个进程队列中排队。如果没有为信号定义信号处理程序,并且默认操作是在转储或不转储核心的情况下终止进程,则终止整个进程。       线程定向信号。有一个特殊的函数可以向特定的线程发送信号:pthread_kill(2)。它可用于将信号从一个线程发送到另一个线程(或自身)。这样,信号将被传送或排队等待特定线程。还存在由诸如SIGSEGV的操作系统生成的每线程定向信号。如果没有为信号定义信号处理程序,默认操作是终止进程,则线程控制信号终止整个过程。