c - 信号处理程序和程序控制流(事件顺序)
问题描述
我一直在阅读 Richard Stevens 的关于 APUE 中的信号和信号处理程序的信息。关于它们我无法理解的一个概念是它们如何在某些时候保证同步性(即使它们确实如此,我也找不到任何反例)。
我发布的代码做了它应该做的事情:父进程从文件中读取(从循环中的标准输入给定),通过管道将它的内容发送到它的子进程(使用内存映射),它替换了一个单词的所有实例换句话说,通过另一个管道将其返回给父级,然后父级将更改的内容打印到标准输出上。但是我不太明白我们如何确定父进程在打印出来之前安全地取回了内容。
换句话说,我怎样才能确定信号是在正确的时刻被捕获的?我知道一个信号可以在任何时候发生,即在父控制流中的任何地方,但是在这里我没有看到在父到达代码的某个部分之前应用了任何“安全措施”,它不应该能够执行在知道孩子完成之前。
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <sys/mman.h>
#include <sys/wait.h>
#include <string.h>
#include <sys/stat.h>
#include <assert.h>
#include <errno.h>
#include <fcntl.h>
#define LINE_SIZE 1024
void error_fatal (char *message);
static void on_sigchld (int signo);
int
main (int argc, char **argv)
{
pid_t pid;
int filedes[2];
int filedes2[2];
char line[LINE_SIZE];
char *src;
char *nl;
char *command;
int count;
char *curr;
int left;
int fd;
struct stat stats;
assert (argc == 3);
if (signal (SIGCHLD, on_sigchld) == SIG_ERR)
error_fatal ("error signal()");
while (fgets (line, LINE_SIZE, stdin) != NULL)
{
if ((nl = strchr (line, '\n')) != NULL)
*nl = 0;
if ((fd = open (line, O_RDONLY)) < 0)
{
if (errno == ENOENT)
{
fprintf (stdout, "%s\n", strerror (errno));
continue;
}
else
error_fatal ("error open()");
}
if (pipe (filedes) < 0)
error_fatal ("error pipe()");
if (pipe (filedes2) < 0)
error_fatal ("error pipe()");
if ((pid = fork ()) < 0)
error_fatal ("error fork()");
else if (pid == 0)
{
if (close (fd) < 0)
error_fatal ("error close()");
if (close (filedes[1]) < 0)
error_fatal ("error close()");
if (close (filedes2[0]) < 0)
error_fatal ("error close()");
if (dup2 (filedes[0], STDIN_FILENO) < 0)
error_fatal ("error dup2()");
if (dup2 (filedes2[1], STDOUT_FILENO) < 0)
error_fatal ("error dup2()");
if ((command = malloc ((strlen (argv[1]) + strlen (argv[2]) +
6) * sizeof (char))) == NULL)
error_fatal ("error malloc()");
sprintf (command, "s/%s/%s/g", argv[1], argv[2]);
execlp ("sed", "sed", command, NULL);
error_fatal ("error exec()");
}
if (close (filedes[0]) < 0)
error_fatal ("error close()");
if (close (filedes2[1]) < 0)
error_fatal ("error close()");
if (fstat (fd, &stats) < 0)
error_fatal ("error fstat()");
if ((src =
mmap (0, stats.st_size, PROT_READ, MAP_FILE | MAP_PRIVATE, fd,
0)) == NULL)
error_fatal ("error mmap()");
curr = src;
left = stats.st_size;
while (left > 0)
{
if ((count = write (filedes[1], curr, left)) < 0)
error_fatal ("error write()");
if (count > 0)
{
left -= count;
curr += count;
}
}
if (close (filedes[1]) < 0)
error_fatal ("error close1()");
if (munmap (src, stats.st_size) < 0)
error_fatal ("error munmap()");
// this is the critical line I'm referring to
while ((count = read (filedes2[0], line, LINE_SIZE)) > 0)
{
if (write (STDOUT_FILENO, line, count) != count)
error_fatal ("error write()");
}
if (count < 0)
error_fatal ("error read()");
if (close (filedes2[0]) < 0)
error_fatal ("error close()");
}
if (ferror (stdin))
error_fatal ("error fgets()");
exit (EXIT_SUCCESS);
}
static void
on_sigchld (int signo)
{
pid_t pid;
for (; (pid = waitpid (-1, NULL, WNOHANG)) > 0;);
if (pid < 0 && errno != ECHILD)
error_fatal ("error waitpid()");
}
static void
error_fatal (char *message)
{
perror (message);
exit (EXIT_FAILURE);
}
解决方案
推荐阅读
- java - Java和黄瓜表达式匹配
- c++ - 为游戏读写文件
- python - keras中卷积神经网络的输入形状
- android - android 9无法在系统应用程序上获取imei数据
- java - 如何使用 Postman 将日期传递给 Java?
- javascript - 如何使用 amchart.js 在图表中隐藏零值?
- certificate - edx 或 coursea 在线证书的价值如何?他们在求职时有帮助吗?
- javascript - 关闭连接时MongoDB拓扑被破坏
- python - 如何使用谷歌云中的云外壳连接到 mysql 实例?
- c# - 如何在单击按钮时请求 SecureString 密码以传递给 Power Shell 进程