UNIX IPC C程序只有父进程才能写入文件,子进程无效

时间:2011-05-07 04:10:28

标签: unix ipc signals

我需要使用Signal在C中编写UNIX进程间通信程序。我希望父进程和子进程写入同一个文件。 结果只显示父文字。我可以使用BSD或System V.请帮助

#include <stdio.h>     /* basic I/O routines.   */
#include <unistd.h>    /* define fork(), etc.   */
#include <sys/types.h> /* define pid_t, etc.    */
#include <sys/wait.h>  /* define wait(), etc.   */
#include <signal.h>

int myFlag = 0;
void myHandler(int);
int child_pid;

int main()
{
    //oldmask = sigblock(sigmask(SIGUSR1));

    sighold(SIGUSR1);
    sighold(SIGINT);
    /* critical region */
    signal (SIGUSR1, myHandler);
    sigrelse(SIGUSR1);
    sigrelse(SIGINT);
    child_pid = fork();


    if (child_pid==0) {

        for ( ; ; ) {
            while(myFlag == 0)
                sigpause(0);
            sigblock (sigmask(SIGUSR1));
            myFlag = 0; 
            FILE *fp=fopen("test","w");
            fwrite("child",1,6,fp);
            fclose(fp); 
            kill(getppid(),SIGUSR1);


        }       
    }  
    if (child_pid>0){
        FILE *fp;
        fp=fopen("test","w");
        fwrite("parent",1,6,fp);
        fclose(fp);

        for ( ; ; ) {
            while(myFlag == 0)
                sigpause(0);
            sigblock (sigmask(SIGUSR1));
            myFlag = 0; 
            fp=fopen("test","w");
            fwrite("parent",1,6,fp);
            fclose(fp); 
        }           
        kill(child_pid, SIGUSR1);
        //kill ()-child_pid ;
    }   

    exit(0);
}

void myHandler(int sigNo) {
    myFlag = 1;
    //signal (SIGUSR1, myHandler);
}

2 个答案:

答案 0 :(得分:1)

您应该首先以追加模式而不是写模式打开文件:

fp = fopen("test", "a");

这会将fp的写入位置定位在文件末尾而不是开头。当您使用"w"打开时,truncate the file and start writing from position 0

   w或wb
  截断为零长度或创建用于写入的文件。

然后你可能想要考虑文件锁定,以防止两个进程同时写入文件。

此外,您的子进程会写出nul终结符:

fwrite("child", 1, 6, fp);

但您的父进程不会:

fwrite("parent", 1, 6, fp);

这可能是也可能不是你的意图,但看起来确实很奇怪。

答案 1 :(得分:1)

你的逻辑是有缺陷的。父进程在等待子进程发出信号之前不会通知子进程。子进程在写入文件并发信号通知父进程之前等待父进程发出信号。

这意味着在父文件中写入文件后,父文件和子文件都会陷入繁忙的循环中,等待另一个人做某事。

此外,虽然我认为这不是代码中的问题,因为调用sigpause(0);会导致编译器认为全局变量可能已更改并需要重新加载,在其他情况下,您可能会想要将myFlag声明为volatile int myFlag;。这会强制编译器在每次引用时从内存中读取或写入其值。

最后,当然,您的程序只会重复写入相同的字节,因为您以"w"(写入)模式而不是"a"(追加)模式打开文件。

这是一个使用POSIX标准调用和技术完成您想要的程序,而不是您正在使用旧的已弃用的过时调用:

#include <stdio.h>     /* basic I/O routines.   */
#include <unistd.h>    /* define fork(), etc.   */
#include <sys/types.h> /* define pid_t, etc.    */
#include <sys/wait.h>  /* define wait(), etc.   */
#include <signal.h>
#include <stdlib.h>

volatile sig_atomic_t myFlag = 0;
void myHandler(int);
int child_pid;

int main()
{
    signal (SIGUSR1, myHandler);
    child_pid = fork();

    if (child_pid==0) {
       for ( ; ; ) {
          while(myFlag == 0)
             ;
          {
             sigset_t oldmask;
             sigset_t usr1;
             sigemptyset(&oldmask);
             sigemptyset(&usr1);
             sigaddset(&usr1, SIGUSR1);
             sigprocmask(SIG_BLOCK, &usr1, &oldmask);
             myFlag = 0;
             sigprocmask(SIG_SETMASK, &oldmask, NULL);
          }
          FILE *fp=fopen("test","a");
          fwrite("child\n",1,6,fp);
          fclose(fp);
          kill(getppid(),SIGUSR1);
       }
    }
    if (child_pid>0){
       FILE *fp;
       fp=fopen("test","a");
       fwrite("parent\n",1,7,fp);
       fclose(fp);

       for ( ; ; ) {
          kill(child_pid, SIGUSR1);
          //kill ()-child_pid ;
          while(myFlag == 0)
             ;
          {
             sigset_t oldmask;
             sigset_t usr1;
             sigemptyset(&oldmask);
             sigemptyset(&usr1);
             sigaddset(&usr1, SIGUSR1);
             sigprocmask(SIG_BLOCK, &usr1, &oldmask);
             myFlag = 0;
             sigprocmask(SIG_SETMASK, &oldmask, NULL);
          }
          fp=fopen("test","a");
          fwrite("parent\n",1,7,fp);
          fclose(fp);
       }
    }

    exit(0);
}

void myHandler(int sigNo) {
    myFlag = 1;
    //signal (SIGUSR1, myHandler);
}