【问题标题】:Linux C signalsLinux C 信号
【发布时间】:2025-09-27 18:40:01
【问题描述】:

我需要使用 SIGUSR1 和 SIGUSR2 并从管道中读取一些文本。一个线程必须读取奇数符号,另一个线程必须读取偶数符号。主线程打开一个 .txt 文件并将信息写入管道,2 个线程从管道读取符号并写入其 .txt 文件。 我尝试使用 sigwait,但它看起来无法正常工作。有任何想法吗? 非常感谢)

#include <sys/types.h>
#include <unistd.h>
#include <iostream>
#include <printf.h>
#include <stdio.h>
#include <sys/wait.h>
#include <stdlib.h>
#include <cerrno>
#include <signal.h>
#include <fcntl.h>
using namespace std;
static bool a=false;
static int c;

main(int argc, char** argv)
{
    int fildes[2]; 
    char ch,ch1,ch2;
    FILE *fp,*f1,*f2;
    int stat,sig;

    sigset_t set1;
    sigset_t set2;
    sigemptyset(&set1);
    sigemptyset(&set2);
    sigaddset(&set1,SIGUSR1);
    sigaddset(&set2,SIGUSR2);
    sigprocmask(SIG_BLOCK,&set1,NULL);
    sigprocmask(SIG_BLOCK,&set2,NULL);

    pid_t p1,p2;
    pipe(fildes); 
    cout<<argv[1]<< " " <<argv[2]<< " " <<argv[3]<<endl;
    fp=fopen(argv[1],"r"); 
    f1=fopen(argv[2],"a");
    f2=fopen(argv[3],"a");
    int chet=2;
    p1=fork();
    if (!p1)
    { 
        do
        {     
            sigwait(&set1,&sig);
            read(fildes[0], &ch1, 1);
            printf("%c",ch1);
            fprintf(f1,"%c",ch1);

        }
        while(!a); 
        exit(0);
    }
    p2=fork();
    if (!p2)
    { 
           do
           {     
                sigwait(&set2,&sig);
                read(fildes[0], &ch2, 1);
                printf("%c",ch2);
                fprintf(f2,"%c",ch2);

           }
           while(!a); 
           exit(0);
    }
    else
    {
        while(!feof(fp))
        {  
              ch=fgetc(fp);
              write(fildes[1],&ch,1);
              if(chet%2==0)
                  kill(p1,SIGUSR1);
                else kill(p2,SIGUSR2);
              chet++;
              //sleep(1/10);
        }
        a=true;

        wait(&stat); 
        close(fildes[0]); 
        close(fildes[1]);
        fclose(f1);
        fclose(f2);
        fclose(fp); 
    }
}

【问题讨论】:

  • 到底发生了什么?看起来它不能正常工作是没有足够的信息
  • 您的代码有一个问题:它没有任何错误处理。零。
  • 我感谢他从问题中删除了错误处理代码以使其更具可读性
  • @user2717954,没有任何反应,如果wait()函数没有被注释,程序一直等待,如果我注释它,程序结束,如果我添加类似kill(p2,SIGUSR2)的东西;在第二个叉子中,它显示我的文本,但所有文本,也不是奇数或偶数符号,所以信息没问题

标签: linux multiprocessing signals


【解决方案1】:

sigwait 等等都很好用。

但是,这里有两个“经典”问题:首先,假设同步行为不成立,其次,缓冲。

不同步的进程:

首先,例如,在我的系统上,给定一个 5 字节的输入文件,父进程写入所有字节(包括 EOF 标记 - 哎呀!)并发送所有信号 在任一子进程甚至调用 sigwait 之前

[parent] read(5, "BaRd\n", 4096)     = 5
[parent] write(4, "B", 1)            = 1
[parent] kill(5404, SIGUSR1)         = 0
[parent] write(4, "a", 1)            = 1
[parent] kill(5405, SIGUSR2)         = 0
[parent] write(4, "R", 1)            = 1
[parent] kill(5404, SIGUSR1)         = 0
[parent] write(4, "d", 1)            = 1
[parent] kill(5405, SIGUSR2)         = 0
[parent] write(4, "\n", 1)           = 1
[parent] kill(5404, SIGUSR1)         = 0
[parent] read(5, "", 4096)           = 0
[parent] write(4, "\377", 1)         = 1                        # Oops! we wrote stdio's EOF marker
[parent] kill(5405, SIGUSR2)         = 0
[parent] wait4(-1,  <unfinished ...>
[child2] rt_sigtimedwait([USR2], NULL, NULL, 8) = 12            # Oops! child2 is going first
[child2] read(3, "B", 1)             = 1
[child2] rt_sigtimedwait([USR2], NULL, NULL, 8 <unfinished ...> # Oops! ordinary UNIX signals don't queue
[child1] rt_sigtimedwait([USR1], NULL, NULL, 8) = 10
[child1] read(3, "a", 1)             = 1
[child1] rt_sigtimedwait([USR1], NULL, NULL, 8

保证一旦您致电fork(),孩子们就准备好了。此外,保证 child1 会首先接受它的信号。确实,在上面,是 child2 接受了一个信号,read()s 首先接受。 (这里的另一个复杂因素是传统的 UNIX 信号不排队。因此,child1 将只接受一个 SIGUSR1,不知道任何先前的冗余信号。)

缓冲:

我推断您的第二个问题是您看不到孩子的输出,无论是终端还是他们的输出文件。这只是a mismatch between your expectations and those output streams' default buffering。更改缓冲,或显式刷新它们,您会看到每个孩子至少写入一个字节。

【讨论】:

  • 我可以对信号的行为做些什么?
  • @JeSa,你可以让父母给第一个孩子一次发信号,然后让孩子互相发信号。