我正在尝试创建简单的信号处理 - 让我们说像终止这个过程。我的程序+主线程中有三个单独的线程。
问题是调用信号会导致当前线程终止,而其他线程仍在运行。
如何将信号发送到剩余的线程?如何在发送这些信号时区分这些信号?
顺便说一句,我必须使用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 :(得分: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的操作系统生成的每线程定向信号。如果没有为信号定义信号处理程序,默认操作是终止进程,则线程控制信号终止整个过程。