我正在尝试创建一个创建文件的程序,将0写入其中,然后使用子进程交替增加该值。例如,子项应将该值递增为1,并将其写回文件。在此之后,父级将其增加到2并将其写入文件。孩子到3岁,依此类推。过程之间的同步通过信号完成。这是源代码:
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <signal.h>
#include <stdlib.h>
void sig_hand (int sig);
int fd;
int main()
{
pid_t pid;
int i;
fd = open ("abc.txt",O_RDWR|O_TRUNC);
if (fd == -1)
{
fd = creat ("abc.txt",S_IRUSR|S_IWUSR);
}
write (fd,"0",2);
if ((pid = fork()) < 0)
{
fprintf (stderr, "Error creating process\n");
exit (1);
} else
{
if (pid == 0)
{
signal (SIGUSR1,sig_hand);
for (;;)
{
pause();
kill (getppid(),SIGUSR1);
}
}
if (pid > 0)
{
sleep (1);
signal (SIGUSR1,sig_hand);
for (i=0;i<5;i++)
{
kill (pid,SIGUSR1);
pause ();
}
kill (pid,SIGTERM);
}
}
return 0;
}
void sig_hand (int sig)
{
int x;
char c;
read (fd,&c,2);
x=atoi(&c);
x++;
printf ("x=%d\n",x);
snprintf (&c,3,"%d",x);
lseek (fd,0,SEEK_SET);
printf ("PID %d is writing\n",getpid());
write (fd,&c,2);
}
运行此程序会产生以下输出:
x=1
PID 4434 is writing
x=1
PID 4433 is writing
x=2
PID 4434 is writing
x=2
PID 4433 is writing
x=3
PID 4434 is writing
x=3
PID 4433 is writing
x=4
PID 4434 is writing
x=4
PID 4433 is writing
x=5
PID 4434 is writing
x=5
PID 4433 is writing
为什么子节点和父节点在一次迭代中递增相同的值?
谢谢!
答案 0 :(得分:2)
问题不在于您的同步,而是您的文件访问。您从文件中读取,回头查找,然后写入文件。您认为下一次阅读将来自哪里?每次写入后,您都需要回到文件的开头。
您还有一些缓冲区溢出,因为您使用char作为单字符字符串。它不起作用,因为你没有空间终止器。
答案 1 :(得分:1)
您的主要问题是您无法以这种方式计时。你的程序在第一次和每次我运行它时都会陷入僵局。一个程序可以(并且经常会)在另一个程序处于等待状态之前发送信号。您完全依赖于调度程序,您无法预测或预测它。因此,正确的程序是阻止信号,因此在您准备好处理之前它不会被传送。以下程序使用sigrocmask
和sigsuspend
来完成此操作。
你的第二个问题是Chris J. Kiick触及的问题。您正在从1字节的内存位置读取和写入2个字节但是,更重要的是,文件描述符在父级和子级之间共享,因此您需要每次都找到正确的位置,否则其他进程会将其留在您不在的位置期待。
#define _POSIX_C_SOURCE 1
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <signal.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>
#define errExit(msg) do { perror(msg); exit(EXIT_FAILURE); } while (0)
void sig_hand(int sig);
int fd;
int main()
{
pid_t pid;
int i;
if ((fd = open("abc.txt", O_RDWR | O_TRUNC)) == -1)
errExit("open");
struct sigaction sa;
sigset_t saveMask, blockMask;
//block SIGUSR1
sigemptyset(&blockMask);
sigaddset(&blockMask, SIGUSR1);
if (sigprocmask(SIG_BLOCK, &blockMask, &saveMask) == -1)
errExit("sigprocmask");
//set up signal handler (both parent & child)
sigemptyset(&sa.sa_mask);
sa.sa_flags = 0;
sa.sa_handler = sig_hand;
if (sigaction(SIGUSR1, &sa, NULL) == -1)
errExit("sigaction");
if (write (fd, "\0", sizeof(char)) == -1)
errExit("initial write");
if ((pid = fork()) < 0)
errExit("fork");
if (pid == 0)
{
for (;;)
{
if (sigsuspend(&saveMask) == -1 && errno != EINTR)
errExit("sigsuspend");
kill(getppid(), SIGUSR1);
}
}
if (pid > 0)
{
for (i = 0;i < 5;i++)
{
kill(pid, SIGUSR1);
if (sigsuspend(&saveMask) == -1 && errno != EINTR)
errExit("sigsuspend");
}
kill(pid, SIGTERM);
}
return 0;
}
void sig_hand(int sig)
{
char c;
if (lseek(fd, 0, SEEK_SET) == (off_t) - 1)
errExit("lseek");
if (read(fd, &c, sizeof(char)) == -1)
errExit("read");
c++;
printf("c = %d\n", c);
if (lseek(fd, 0, SEEK_SET) == (off_t) - 1)
errExit("lseek");
printf("PID %d is writing\n", getpid());
if (write (fd, &c, sizeof(char)) == -1)
errExit("write");
}
答案 2 :(得分:1)
这是更正后的sig_hand
void sig_hand (int sig) {
int x;
char c[3];
read (fd,c,2);
x=atoi(c);
x++;
printf ("x=%d\n",x);
snprintf (c,3,"%d",x);
lseek (fd,0,SEEK_SET);
printf ("PID %d is writing\n",getpid());
write (fd,c,2);
lseek (fd,0,SEEK_SET);
}