试图用 pipe() 在两个进程之间进行通信,会破坏程序。

问题描述 投票:0回答:1

我试图在C语言的两个进程之间使用管道进行通信。 在打印 "hi\n "之前,一切都很正常。输出的结果是

(8841) Child here stopping self
(8841) SAYS: 19
DATA WRITED
C: 8
(8841) CONTINUING

这是该程序的简化版。我知道读的部分可以用,但写的部分似乎不行,因为它从来没有打印出 "hi/n"。有什么线索可以告诉我为什么会这样?

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

volatile sig_atomic_t sigchld = 0;

void sigchldHandler(){
    sigchld = 1;
    return;
}

int main(){

    sigset_t mask,prev;
    signal(SIGCHLD, sigchldHandler);
    sigemptyset(&mask);
    sigaddset(&mask, SIGCHLD);

    int pid = fork();

    int fd[2];
    pipe(fd);

    sigprocmask(SIG_BLOCK, &mask, &prev);
    if (pid == 0){
        dup2(STDIN_FILENO,fd[0]);
        printf("(%d) Child here stopping self\n",getpid());
        raise(SIGSTOP);
        printf("(%d) CONTINUING\n",getpid());
        char* hello = malloc(sizeof("hi\n"));
        read(STDIN_FILENO,hello,sizeof("hi\n"));
        printf("%s",hello);
        exit(0);
    }
    sleep(0.1);
    sigprocmask(SIG_SETMASK, &prev,NULL);
    while(1){
        if (sigchld){
            int status;
            int p = waitpid(-1,&status,WNOHANG|WUNTRACED);
            if (WIFSTOPPED(status)){
                if (WSTOPSIG(status) == SIGSTOP){
                    printf("(%d) SAYS: %d\n",p, WSTOPSIG(status));
                    kill(pid,SIGCONT);
                    printf("DATA WRITED\n");
                    char* h = "hi\n";
                    int c=write(fd[1],h,sizeof(h));
                    printf("C: %i\n",c);
                    break;
                }
            }
            sigchld = 0;
        }
    }
} 
c linux pipe fork
1个回答
2
投票

主要问题

你的关键问题是,你叫 pipe() 之后 你叫 fork(). 这意味着这两个进程有完全独立的管道,它们并没有相互交谈。

次要问题

当然也有其他问题。

  • 你有(在父母)。int c=write(fd[1],h,sizeof(h));. 你正在写8个字节(你的输出包括 C: 8 因为变量 h 是一个大小的指针 8 (你是在64位系统上)。 然而,这个字符串只指向4个字节--你应该使用 strlen() 或在那里,以限制写入的数据量。

  • 你没有关闭足够多的文件描述符。

  • 你的参数是 dup2() 颠倒了。 这也是至关重要的。

  • 仅仅对4个字节的数据使用动态分配似乎很奇怪,但它应该可以工作。

  • 你应该把PID和值一起打印在 hello 儿中(为了保持一致性,如果没有别的原因)。 你这样做很好,其他的打印。

  • 父程序可能应该在循环后(关闭管道后)等待子程序。

  • 循环中的 sleep() 函数取一个整数;调用 sleep(0.1) 睡眠时间为零秒。 对于亚秒级睡眠,你需要 nanosleep() 或者也许。usleep() (较早,不再是POSIX的一部分,但可广泛使用,而且更容易使用)。

这里是工作代码。

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

volatile sig_atomic_t sigchld = 0;

static void sigchldHandler(int signum)
{
    sigchld = signum;
}

int main(void)
{
    sigset_t mask, prev;
    signal(SIGCHLD, sigchldHandler);
    sigemptyset(&mask);
    sigaddset(&mask, SIGCHLD);

    int fd[2];
    pipe(fd);

    int pid = fork();

    sigprocmask(SIG_BLOCK, &mask, &prev);

    if (pid == 0)
    {
        /* Child */
        dup2(fd[0], STDIN_FILENO);
        close(fd[0]);
        close(fd[1]);
        printf("(%d) Child here stopping self\n", getpid());
        raise(SIGSTOP);
        printf("(%d) CONTINUING\n", getpid());
        char *hello = malloc(sizeof("hi\n"));
        int nbytes = read(STDIN_FILENO, hello, sizeof("hi\n"));
        printf("(%d) received %d bytes: %.*s\n", getpid(), nbytes, nbytes, hello);
        exit(0);
    }

    /* Parent */
    close(fd[0]);
    nanosleep(&(struct timespec){.tv_sec = 0, .tv_nsec = 100000000}, NULL);
    sigprocmask(SIG_SETMASK, &prev, NULL);
    while (1)
    {
        if (sigchld)
        {
            int status;
            int p = waitpid(-1, &status, WNOHANG | WUNTRACED);
            if (WIFSTOPPED(status))
            {
                if (WSTOPSIG(status) == SIGSTOP)
                {
                    printf("(%d) SAYS: %d\n", p, WSTOPSIG(status));
                    kill(pid, SIGCONT);
                    char *h = "hi\n";
                    int c = write(fd[1], h, strlen(h));
                    printf("DATA WRITTEN: %i\n", c);
                    close(fd[1]);
                    break;
                }
            }
            sigchld = 0;
        }
    }
    int corpse;
    int status;
    while ((corpse = wait(&status)) > 0)
        printf("PID %d exited with status 0x%.4X\n", corpse, status);
    return 0;
}

输出样本:

(66589) Child here stopping self
(66589) SAYS: 17
DATA WRITTEN: 3
(66589) CONTINUING
(66589) received 3 bytes: hi

PID 66589 exited with status 0x0000

17(在运行macOS Mojave 10.14.6的Mac上)和19(在Linux盒子上)之间的差异是正常的;信号号的实际值并没有被POSIX标准化(虽然信号 1 SIGHUP 至15岁 SIGTERM 在各系统中是一样的,因为它们是第7版Unix的标准配置)。)

© www.soinside.com 2019 - 2024. All rights reserved.