C Linux从文件读取异常行为

C Linux从文件读取异常行为,c,linux,unix,signals,C,Linux,Unix,Signals,我试图创建一个程序,创建一个文件,将0写入其中,然后使用子进程交替递增该值。例如,子级应将该值增加到1,并将其写回文件。在此之后,父级将其增量为2,并将其写入文件中。这孩子要3岁,依此类推。进程之间的同步通过信号完成。以下是源代码: #include <stdio.h> #include <fcntl.h> #include <unistd.h> #include <signal.h> #include <stdlib.h> void

我试图创建一个程序,创建一个文件,将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);
}
为什么子代和父代在一次迭代中递增相同的值


谢谢

问题不在于同步,而在于文件访问。从文件中读取内容,返回到开头,然后写入文件。你认为下一次阅读会从哪里来?您还需要在每次写入后查找回文件的开头


您还存在一些缓冲区溢出,因为您将字符用作单个字符串。它不是那样工作的,因为您没有空终止符的空间。

问题不在于您的同步,而在于您的文件访问。从文件中读取内容,返回到开头,然后写入文件。你认为下一次阅读会从哪里来?您还需要在每次写入后查找回文件的开头


您还存在一些缓冲区溢出,因为您将字符用作单个字符串。它不能那样工作,因为你没有空终止符的空间。

你的主要问题是你不能用那种方式对信号计时。你的程序第一次死机,每次我运行它。一个程序可以(通常会)在另一个程序等待信号之前发送信号。您完全依赖于调度程序,无法预测或预测它。因此,正确的程序是阻止信号,以便在您准备好处理它之前不会发送信号。下面的程序使用
sigrocmask
sigssuspend
来实现这一点

你的第二个问题就是被提到的问题。您正在从一个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");
}
\define\u POSIX\u C\u源代码1
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#定义errExit(msg)do{perror(msg);exit(exit_FAILURE);}while(0)
无效信号(内部信号);
int-fd;
int main()
{
pid_t pid;
int i;
如果((fd=open(“abc.txt”,O|RDWR | O|TRUNC))=-1)
退出(“开放”);
struct-sigaction-sa;
sigset\u t saveMask,blockMask;
//块SIGUSR1
SIGEPTYSET(和块掩码);
sigaddset(和块掩码,SIGUSR1);
if(sigprocmask(SIG_块、块掩码和保存掩码)=-1)
errExit(“sigprocmask”);
//设置信号处理程序(父级和子级)
sigemptyset(和sa.sa_面具);
sa.sa_标志=0;
sa.sa_handler=sig_hand;
if(sigaction(SIGUSR1,&sa,NULL)=-1)
errExit(“sigaction”);
如果(写入(fd,“\0”,sizeof(char))=-1)
errExit(“初始写入”);
如果((pid=fork())<0)
退出(“fork”);
如果(pid==0)
{
对于(;;)
{
如果(SIGSSUSPEND(&saveMask)=-1&&errno!=EINTR)
errExit(“sigsuspend”);
kill(getppid(),SIGUSR1);
}
}
如果(pid>0)
{
对于(i=0;i<5;i++)
{
kill(pid,SIGUSR1);
如果(SIGSSUSPEND(&saveMask)=-1&&errno!=EINTR)
errExit(“sigsuspend”);
}
kill(pid,SIGTERM);
}
返回0;
}
无效信号手(内部信号)
{
字符c;
if(lseek(fd,0,SEEK_SET)==(off_t)-1)
errExit(“lseek”);
if(读取(fd,&c,sizeof(char))=-1)
退出(“读取”);
C++;
printf(“c=%d\n”,c);
if(lseek(fd,0,SEEK_SET)==(off_t)-1)
errExit(“lseek”);
printf(“PID%d正在写入\n”,getpid());
if(写入(fd,&c,sizeof(char))=-1)
退出(“写入”);
}

您的主要问题是无法以这种方式对信号计时。你的程序第一次死机,每次我运行它。一个程序可以(通常会)在另一个程序等待信号之前发送信号。您完全依赖于调度程序,无法预测或预测它。因此,正确的程序是阻止信号,以便在您准备好处理它之前不会发送信号。下面的程序使用
sigrocmask
sigssuspend
来实现这一点

你的第二个问题就是被提到的问题。您正在从一个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");
}
\define\u POSIX\u C\u源代码1
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#定义errExit(msg)do{perror(msg);exit(exit_FAILURE);}while(0)
无效信号(内部信号);
int-fd;
int main()
{
pid_t pid;
int i;
如果((fd=open(“abc.txt”,O|RDWR | O|TRUNC))=-1)
退出(“开放”);
struct-sigaction-sa;
sigset\u t saveMask,blockMask;
//块SIGUSR1
SIGEPTYSET(和块掩码);
sigaddset(和块掩码,SIGUSR1);
if(sigprocmask(SIG_块、块掩码和保存掩码)=-1)
errExit(“sigprocmask”);
//设置信号处理程序(父级和子级)
sigemptyset(和sa.sa_面具);
sa.sa_标志=0;
sa.sa_handler=sig_hand;
if(sigaction(SIGUSR1,&sa,NULL)=-1)
errExit(“sigaction”);
如果(写入(fd,“\0”,sizeof(char))=-1)
errExit(“初始写入”);
如果((pid=fork())<0)
退出(“fork”);
如果(pid==0)
{
对于(;;)
{
如果(SIGSSUSPEND(&saveMask)=-1&&e
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);
}