Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Does write system call need the data to be read to give >-1 return?

Tags:

c

posix

ipc

Sorry for the basic question, but I can't find a straight answer that I can understand on the documentation or with generative AI.

When I do a write call over a pipe between a parent and child process, will write only return something != -1 if the data is read by a read system call?

For instance, take the following code below:

int main(int argc, char* argv[]) {
  int workers = 4;
  int pfd[2];
  int pipe_result = pipe(pfd);
  if(pipe_result != 0) {
    fail("Can't create pipe");
  }
  // Parent doesn't need write channel
  close(pfd[1]);

  for(int i = 0; i < workers; i++) {
    pid_t pid = fork();
    // Child
    if(pid == 0) {
      // Child doesn't need read channel
      close(pfd[0]);

      int count = 101;

      // Write count to pipe
      int len_sent = write(pfd[1], &count, sizeof(count));
      printf("\nChild id: %d Sent %d bytes, count: %d", getpid(), len_sent, count);
      
      // Exit so that the child processes don't loop
      close(pfd[1]);
      exit(0);
    }
    else {
      int par_count;
      // Read
      int len = read(pfd[0], &par_count, sizeof(par_count));
      printf("\nlen: %d par_count: %d", len, par_count);
    }
  }
  
  // Close read buffer in parent
  close(pfd[0]);
  return 0;
}

That code will generally output indicating that 0 or 1 write and read calls were successful. If I move the reads to be after all write calls are done (code below), then everything reports fine.

int main(int argc, char* argv[]) {
  int workers = 4;
  int pfd[2];
  int pipe_result = pipe(pfd);
  if(pipe_result != 0) {
    fail("Can't create pipe");
  }

  for(int i = 0; i < workers; i++) {
    pid_t pid = fork();
    // Child
    if(pid == 0) {
      // Child doesn't need read channel
      close(pfd[0]);

      int count = 101;

      // Write count to pipe
      int len_sent = write(pfd[1], &count, sizeof(count));
      printf("\nChild id: %d Sent %d bytes, count: %d", getpid(), len_sent, count);
      
      // Exit so that the child processes don't loop
      close(pfd[1]);
      exit(0);
    }
  }
  
  // Parent doesn't need write channel
  close(pfd[1]);

    // Parent
  for(int i = 0; i < workers; i++) {
    int par_count;
    // Read
    int len = read(pfd[0], &par_count, sizeof(par_count));
    printf("\nlen: %d par_count: %d", len, par_count);
  }

  // Close read in parent
  close(pfd[0]);
  return 0;
}

Why does this change affect the return of the write calls? I understand why it affects the read returns - that makes sense to me. But I don't understand why this change makes the write calls report -1. Is the return of write dependent on the data being read by a read call?

like image 298
Sterling Mcleod Avatar asked Oct 17 '25 13:10

Sterling Mcleod


1 Answers

To answer the question in the title: No. write() simply stores the data in the pipe buffer and returns immediately, it doesn't wait for the pipe to be read. When not -1, the return value is the number of bytes that were written to the buffer.

The problem in your code is that you have close(pfd[1]) before the loop that forks all the children. As a result, the children inherit the closed write end of the pipe, so they can't write to it.

You should move that call after the loop.

like image 56
Barmar Avatar answered Oct 19 '25 04:10

Barmar