我试图在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;
}
}
}
你的关键问题是,你叫 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的标准配置)。)