【问题标题】:Sending signal to all threads向所有线程发送信号
【发布时间】:2014-06-30 09:36:59
【问题描述】:

我正在尝试创建简单的信号处理 - 比如说终止进程。我的程序+主线程中有三个单独的线程。

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

如何将信号发送到其余线程?我如何在发送这些信号时区分它们?

顺便说一句,这里得用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;
}

【问题讨论】:

    标签: c linux multithreading posix


    【解决方案1】:

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

    信号:标准信号(即 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。理想情况下,您想做非常简单的事情,例如在信号处理程序中设置一个全局开关并退出。因此,如果这不仅仅是脑死亡的课堂作业,您应该重新考虑这一点。

    我建议您详细说明您对该计划的目标是什么,您可以就如何实现它获得一些建议。

    【讨论】:

      【解决方案2】:

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

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

      哪个线程接收到信号?

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

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2016-11-06
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-01-06
        • 1970-01-01
        • 2015-08-21
        相关资源
        最近更新 更多