【问题标题】:Why is my pipe in C not working?为什么我在 C 中的管道不起作用?
【发布时间】:2011-06-16 10:54:23
【问题描述】:

作为练习,我需要使用信号处理程序,并在获得信号时使用管道在两个进程之间发送一些消息。下面是我的源代码。当我运行它时,我可以让管道工作,两个进程都可以交谈,只要我在它们的主方法中调用管道(在本例中为 process1() 和 process2() )。 但我想使用信号处理程序中的管道。但是现在管道不工作了。 这是我得到的一些输出:

3 - 4 and 5 - 6
Segv at 8825
USR1 at 8824
898 sent to 4
130 received on 3
130

'898' 和 '130' 应该相等,但不相等。 我知道管道工作正常,所以我认为这与信号有关...... 但是什么...?

源码:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/wait.h>

int fd1[2], fd2[2], status;
int cpid, cpoid;

void process1() {   
    cpid = getpid();        /*What's my process ID?*/
    cpoid = cpid + 1;       /*And what's the other process ID?*/

    close(fd1[0]);
    close(fd2[1]);

    while (1) {}
}

void process2() {   
    cpid = getpid();
    cpoid = cpid - 1;

    close(fd1[1]);
    close(fd2[0]);

    raise(SIGSEGV);         /*Start with a SegV signal*/

    while (1) {}
}

/*Method to send a message to the other process, by pipe*/
void send (int msg) {
    if (cpid < cpoid) {
        write(fd1[1], &msg, 1);
        printf("%d sent to %d\n", msg, fd1[1]);
    } else {
        write(fd2[1], &msg, 1);
        printf("%d sent to %d\n", msg, fd2[1]);
    }
}

/*Method to receive a message from the other process*/
int receive () {
    int msg = 0;
    if (cpid < cpoid) {
        read(fd2[0], &msg, 1);
        printf("%d received on %d\n", msg, fd2[0]);
    } else {
        read(fd1[0], &msg, 1);
        printf("%d received on %d\n", msg, fd1[0]);
    }
    return msg;
}

/*The SegV Signal handler*/
void segvHandler() {
    int y = -1;
    printf("Segv at %d\n", cpid);
    kill(cpoid, SIGUSR1);           /*Send an USR1 Signal to the other proces*/

    while (y != 898) {
        y = receive();
        printf("%d\n", y);
    }
}

/*The Usr1 Signal handler*/
void usr1Handler() {
    int x = 898;
    printf("USR1 at %d\n", cpid);

    send(x);
}

int main (int argc, char *argv[]) {

    if (pipe(fd1) < 0) {
        fprintf (stderr, "Could not make pipe\n");
        return (EXIT_FAILURE);
    }
    if (pipe(fd2) < 0) {
        fprintf (stderr, "Could not make pipe\n");
        return (EXIT_FAILURE);
    }
    printf("%d - %d and %d - %d\n", fd1[0], fd1[1], fd2[0], fd2[1]);    /*Pipe numbers*/

    signal(SIGUSR1, usr1Handler);   /*Signal handlers*/
    signal(SIGSEGV, segvHandler);

    if (fork() != 0) {
        process1();
    } else {
        process2();
    }
    waitpid(-1, &status, 0);

    return EXIT_SUCCESS;
}

【问题讨论】:

  • 您不应该在信号处理程序中执行任何重要的 I/O。应该只是在某处设置一个标志,然后有一个作用于该标志的主循环。不确定这是否是您的问题,但这是标准指南。
  • 作为预告片,898 是 0x382,130 是 0x82。编辑:因此,如果发送和接收仅对单个字节(char 类型)进行操作,那么整数将被截断,因为它被隐式转换为 char 类型。
  • printf() 不是异步安全的,不要在信号处理程序中使用它。
  • 您不能依赖仅相差一个的 pid。要获取其他进程的 pid,必须在 fork 处对其进行跟踪或通过管道写入。
  • 当然,它并不是那么出色的代码,但这只是让我看看它是如何工作的,以及为什么它不是。但我会在继续时牢记您的建议。谢谢!

标签: c segmentation-fault pipe signal-handling


【解决方案1】:

一些故障基于快速浏览。

  • printf() 不是异步信号安全的;不要在信号处理程序中调用它。

  • 您正在读写 1 个字节,这很可能小于 sizeof(int)。

  • 您不能假设 PID 是连续的。在父进程中,fork() 的返回值给出了子进程的 PID。在子进程中,如果父进程在 fork() 之前存储了 getpid() 的返回值,那么你就有了;否则请参阅 getppid()。

【讨论】:

    【解决方案2】:

    如 cmets 中所述,您不应该 在信号处理程序中调用 printf,但这可能不是问题。除非 int 在您的机器上是一个字节,否则问题是您没有写入或读取整个 int,因为您只将一个字节写入管道。 (将代码更改为:write( fd[ 1 ], &msg, sizeof msg ) 并在读取时进行相同的更改。)

    【讨论】:

      猜你喜欢
      • 2014-04-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-05-27
      • 2021-11-16
      • 2021-04-14
      • 2016-08-25
      • 1970-01-01
      相关资源
      最近更新 更多