c语言 - 无法正确使用系统调用 write()



赋值

用C/Posix (Linux环境)编写一个程序,同步父进程和子进程(使用信号),在txt文件的第一个位置从1n(由用户指定)逐一读取和写入数字。

#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>
#include <fcntl.h>
int main(int argc, char const *argv[])
{
int n = atoi(argv[1]);
int i;
int fd = open("exercise.txt", O_RDWR | O_CREAT, 0777);
pid_t pid = fork();
if (!pid) {
for (i = 1; i <= (n / 2); i++) {
pause();
char c[2];
sprintf(c, "%d", i + 1);
write(fd, c, sizeof(c));
kill(pid, SIGUSR1);
}
}
else {
for (i = 1; i <= (n / 2); i++) {
char c[2];
sprintf(c, "%d", i);
write(fd, c, sizeof(c));
kill(pid, SIGUSR1);
pause();
}
}
return 0;
}

对于我传递给程序的每个数字,我总是找到一个只有"1"的txt文件。写在上面而不是1234…我做错了什么?

子进程将在进入循环的第一次迭代时立即pause,等待接收信号。

在其循环的第一次迭代中,父进程将两个字节的数据写入文件,将SIGUSR1信号发送给子进程,然后自己发送pause,等待接收信号。

接收SIGUSR1时的默认动作是终止进程。

pause()仅在信号被捕获且信号捕获函数返回时返回。

因此子进程除了可能等待信号之外什么都不做,当然几乎立即终止。

父进程保持暂停状态,等待信号。


一些笔记:

signal(7)查看信号的概述。

指令,据我所知,write在一个进程中,read在另一个进程中。你的程序试图在两个进程中写入。

char c[2];
sprintf(c, "%d", i); /* or i + 1 */

c的大小只足够存储长度最多为1的字符串(可选一个字符,加上结束null的字节,总是)。这有未定义行为的风险,因为如果sprintf的第三个参数在[0,9]范围之外,缓冲区中将没有足够的空间。

子进程中,pid将是kill(pid, SIGUSR1);中的0。Fromkill(2):

如果pid等于0,则将sig发送给调用进程所属进程组中的每个进程。

在分叉之前打开文件,表示两个进程共享相同的文件描述。在一个进程中更改文件偏移量(通过读、写或查找)将改变另一个进程中的偏移量。

在任何情况下,指令都是在文件(lseek(2))的开头写和读。


您需要捕获SIGUSR1的交付,否则将发生流程终止的默认操作。

此外,killpause的模式不足以避免竞争条件,即在进程暂停等待信号之前发送信号。这个答案涵盖了问题和解决方案。详细的方法是使用sigprocmask(2)正常延迟(阻塞)信号的传递,然后使用sigsupend(2)临时处理这些信号。

下面是一个粗略的示例,缺少错误处理,其中父进程写入,而子进程读取。
#include <fcntl.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/wait.h>
#include <unistd.h>
void pdie(const char *msg)
{
perror(msg);
exit(EXIT_FAILURE);
}
void handler(int sig)
{
signal(sig, handler);
}
int main(int argc, char const *argv[])
{
if (argc < 2)
return EXIT_FAILURE;
int fd = open("exercise.txt", O_RDWR | O_CREAT | O_TRUNC, 0777);
if (-1 == fd)
pdie("open");
int n = atoi(argv[1]);
if (n < 1)
n = 10;
sigset_t set, old;
sigemptyset(&set);
sigaddset(&set, SIGUSR1);
sigprocmask(SIG_BLOCK, &set, &old);
signal(SIGUSR1, handler);
pid_t pid = fork();
if (-1 == pid)
pdie("fork");
for (int i = 0; i < n; i++) {
char buf[32];
if (pid) {
/* parent writes */
int len = snprintf(buf, sizeof buf, "%d", i + 1);
lseek(fd, 0, SEEK_SET);
write(fd, buf, (size_t) len);
kill(pid, SIGUSR1);
sigsuspend(&old);
} else {
/* child reads */
sigsuspend(&old);
memset(buf, 0, sizeof buf);
lseek(fd, 0, SEEK_SET);
ssize_t bytes = read(fd, buf, sizeof buf - 1);
printf("Child read %zd bytes: %sn", bytes, buf);
kill(getppid(), SIGUSR1);
}
}
close(fd);
if (pid)
waitpid(pid, NULL, WUNTRACED);
}

最新更新