title: Simple synchronization with C signals
body: <p>I'm trying to solve an exercise which requires that : "the starting process must fork two times. The father and the children must synchronize to write, one after another, in the first position of a temporary file reading the characters written on three different files (one for each process). The program must use signals to implement the synchronization mechanism."</p>
  
  <p>So far i've tried to solve this by doing so :</p>
  
  <ul>
  <li>P1 (the father) starts reading/writing first. Before stopping himself (through a call to the raise function), he sends a SIGCONT signal to wake up F2 (the second child)</li>
  <li>F2 reads from his file and writes on the temp file. He then stops himself too, and sends a SIGCONT signal to wake up F1 (the first child)</li>
  <li>F1 does the same as F2, but wakes up P1 and so on...</li>
  </ul>
  
  <p>However, i can't get the code working (in some cases, after changing the order of the readings and writings, i got most of the latter in output but the program behavior was always erratic and never terminated). </p>
  
  <p>Here's my code :</p>
  
  <pre><code>#include &lt;stdio.h&gt;
  #include &lt;stdlib.h&gt;
  #include &lt;unistd.h&gt;
  #include &lt;sys/types.h&gt;
  #include &lt;fcntl.h&gt;
  #include &lt;string.h&gt;
  #include &lt;signal.h&gt;
  
  #define TEMP_PATH "/tmp/mytempfile"
  
  int main(int argc, char *argv[]){
  
  FILE *writeFp;
  FILE *rfpF1;
  FILE *rfpF2;
  FILE *rfpP1;
  pid_t pid1, pid2;
  
  char car;   
  char sizeOfChar = sizeof(char);
  
  if (argc != 4 || !strcmp(argv[1], "--help")){
      fprintf(stderr, "Usage : %s filePath1 filePath2 filePath3\n", argv[0]);
      exit(EXIT_FAILURE);
  }
  
  if (access(argv[1], F_OK)==-1){
      perror("access 1 error");
      exit(EXIT_FAILURE);
  }
  
  if (access(argv[2], F_OK)==-1){
      perror("access 2 error");
      exit(EXIT_FAILURE);
  }
  
  if (access(argv[3], F_OK)==-1){
      perror("access 3 error");
      exit(EXIT_FAILURE);
  }
  
  if((writeFp = fopen(TEMP_PATH, "w")) == NULL){
      fprintf(stderr, "Can't open temp file on writing.\n");
      exit(EXIT_FAILURE);
  }
  
  if ((rfpP1 = fopen(argv[3], "r")) == NULL){
      fprintf(stderr, "Can't open %s on reading.\n", argv[3]);
      exit(EXIT_FAILURE);
  }   
  
  switch(pid1 = fork()){
      case -1:
              perror("fork error");
              exit(EXIT_FAILURE);
  
      case 0:
              /* F1 : first child */
  
              if ((rfpF1 = fopen(argv[1], "r")) == NULL){
                  fprintf(stderr, "Can't open %s on reading.\n", argv[1]);
                  exit(EXIT_FAILURE);
              }
  
              raise(SIGSTOP);
              while(fscanf(rfpF1, "%c", &amp;car) != EOF){
  
                  if(fseek(writeFp, 0L, SEEK_SET) == -1){
                      perror("fseek error");
                      exit(EXIT_FAILURE);
                  }
                  if(fprintf(writeFp, "%c", car) != 1){
                      fprintf(stderr, "fprintf error. Terminating...\n");
                      exit(EXIT_FAILURE);
                  }                   
  
                  if(kill(getppid(), SIGCONT) == -1){
                      perror("F1 kill error");
                      exit(EXIT_FAILURE);
                  }
  
                  printf("F1 : i've written '%c'\n", car); fflush(stdout);
  
                  // If with the next read EOF is reached, the process doesn't have to stop...
                  if(fscanf(rfpF1, "%c", &amp;car) == EOF)
                      break;
                  else{
                      if(fseek(rfpF1, -sizeOfChar, SEEK_CUR)){
                          perror("fseek error");
                          exit(EXIT_FAILURE);
                      }
                      raise(SIGSTOP);
                  }
              }
  
              fclose(rfpF1);              
              exit(EXIT_SUCCESS);
  
  
      default :
              break;  
  
  }
  
  
  switch(pid2 = fork()){
      case -1:
              perror("fork 2 error");
              exit(EXIT_FAILURE);
  
      case 0:
              /* F2 : second child */
  
              if ((rfpF2 = fopen(argv[2], "r")) == NULL){
                  fprintf(stderr, "Can't open %s on reading.\n", argv[2]);
                  exit(EXIT_FAILURE);
              }
  
              raise(SIGSTOP);
              while(fscanf(rfpF2, "%c", &amp;car) != EOF){
  
                  if(fseek(writeFp, 0L, SEEK_SET) == -1){
                      perror("fseek error");
                      exit(EXIT_FAILURE);
                  }
                  if(fprintf(writeFp, "%c", car) != 1){
                      fprintf(stderr, "fprintf error. Terminating...\n");
                      exit(EXIT_FAILURE);
                  }               
  
                  if(kill(pid1, SIGCONT) == -1){
                      perror("F2 kill error");
                      exit(EXIT_FAILURE);
                  }
  
                  printf("F2 : i've written '%c'\n", car); fflush(stdout);
  
                  if(fscanf(rfpF2, "%c", &amp;car) == EOF)
                      break;
                  else{
                      if(fseek(rfpF2, -sizeOfChar, SEEK_CUR)){
                          perror("fseek error");
                          exit(EXIT_FAILURE);
                      }
                      raise(SIGSTOP);
                  }
              }
  
              fclose(rfpF2);  
              exit(EXIT_SUCCESS);
      default:    
              /* P1 : Father */
  
              // Wait for the children to be interrupted by SIGSTOP (which changes their states)
              if(wait(NULL) == -1){
                  perror("wait 1 error");
                  exit(EXIT_FAILURE);
              }
  
              if(wait(NULL) == -1){
                  perror("wait 2 error");
                  exit(EXIT_FAILURE);
              }
  
              // P1 is the first to be reading and writing...
              while(fscanf(rfpP1, "%c", &amp;car) != EOF){
  
                  if(fseek(writeFp, 0L, SEEK_SET) == -1){
                      perror("fseek error");
                      exit(EXIT_FAILURE);
                  }
                  if(fprintf(writeFp, "%c", car) != 1){
                      fprintf(stderr, "fprintf error. Terminating...\n");
                      exit(EXIT_FAILURE);
                  }
  
                  if(kill(pid2, SIGCONT) == -1){
                      perror("P kill error");
                      exit(EXIT_FAILURE);
                  }
  
                  printf("P1 : i've written '%c'\n", car); fflush(stdout);
  
                  if(fscanf(rfpP1, "%c", &amp;car) == EOF)
                      break;
                  else{
                      if(fseek(rfpP1, -sizeOfChar, SEEK_CUR)){
                          perror("fseek error");
                          exit(EXIT_FAILURE);
                      }
                      raise(SIGSTOP);
                  }
  
              }
  
              fclose(rfpP1);  
              break;
  }
  
  // Wait for the children...
  if(wait(NULL) == -1){
      perror("wait 1 error");
      exit(EXIT_FAILURE);
  }
  
  if(wait(NULL) == -1){
      perror("wait 2 error");
      exit(EXIT_FAILURE);
  }
  
  fclose(writeFp);
  exit(EXIT_SUCCESS);
  }
  </code></pre>