In C, how does the read function “know” when there is nothing to read?

In the program below (which is not mine, but the one I changed), the child process makes two entries in the pipe. When I run the program, I get the following output:

Received string: Hello, world! This is the child process. 

How is it that reading performed by the parent process captures both of these lines from the channel buffer? What (if anything) prevents the parent from accepting after it reads the first line (or the first char of the first line, for that matter) that there is nothing to read from the buffer and exit?

Suggested program:

 int main(void) { int fd[2], nbytes; pid_t childpid; char string[] = "Hello, world!\n"; char string2[] = "This is the child process.\n"; char readbuffer[80]; pipe(fd); if((childpid = fork()) == -1) { perror("fork"); return 1; } if(childpid == 0) { /* Child process closes pipe input file descriptor */ close(fd[0]); /* Send "string" through the output side of pipe */ write(fd[1], string, (strlen(string))); write(fd[1], string2, (strlen(string2)+1)); return 1; } else { /* Parent process closes pipe output file descriptor */ close(fd[1]); /* Read in a string from the pipe */ nbytes = read(fd[0], readbuffer, sizeof(readbuffer)); printf("Received string: %s", readbuffer); } return 0; } 
+7
c pipe fork parent-child
source share
5 answers

The key here is read() 80 buffer size.

Usually read() blocks the process that calls it (it is set in the idle state) until certain conditions are met, for example:

  • The requested buffer is full.
  • less data than requested ( EOF ) or error occurred
  • the signal wakes up the process (like ^C ), this may be your case, the output of the child process and the system send the broken channel signal to the parent (the wake and read() process receive the entire buffer)

Note that these conditions depend on the subsystem you are reading, in your case a pipe . A subsystem that can have different properties, such as buffer size. An absurd example: if the size of the channel buffer on the kernel side was less than or equal to your first record, the reading process woke up earlier, returning a truncated buffer.

+1
source share

The parent will read a maximum of 80 bytes. Thus, the first write system call (as well as the second) will put the first line in the kernel buffer relative to the channel. The read system call will read no more than 80 bytes, so it will query the kernel for the data, and the kernel will return the first 80 bytes of data in the buffer (therefore, it is impossible to read only the first character of a line with a single write of the entire line and one lock that reads 80 bytes )

As you said, there is no synchronization between child and parent. In fact, on my Linux system, your program sometimes only prints the first line, sometimes it prints and.

The problem is the classic Race Condition problem, sometimes the child will write only the first line, then the parent chart, and he will read the first line, then the program will end (or the control will return to the read child, the child will write the second line to the buffer buffer, but no one won't really read the data).

You have to put some synchronization functions in your program, an example would be setting the child to wait after close(fd[1]);

 [...] else { /* Parent process closes up output side of pipe */ close(fd[1]); /* Synchronize parent and child */ wait(NULL); /* Read in a string from the pipe */ nbytes = read(fd[0], readbuffer, sizeof(readbuffer)); printf("Received string: %s", readbuffer); } [...] 

Then the parent will read the data only when two lines are correctly placed in the buffer.

0
source share

This is an example of how to write in a pipe.

This example is for a parent record for a child, but the logic is very similar, regardless of the direction of the data stream.

  close(pipefd[0]); /* Close unused read end */ write(pipefd[1], argv[1], strlen(argv[1])); close(pipefd[1]); /* Reader will see EOF */ wait(NULL); /* Wait for child to exit */ exit(EXIT_SUCCESS); 

Among other things, this means that the calling read () element will get a return value of 0 when everything is read from the pipe.

it also means that the reader reads in a loop until an indication of the error condition is returned or 0 is returned.

0
source share

... how does the read function “know” when there is nothing to read?

On success, read() returns as much as is available in the base object, but no more than what was requested.

From man 3 read (POSIX) :

After successful completion, when nbyte is greater than 0, read () should note the update of the st_atime field of the file and return the number of bytes read. This number will never be more than nbyte. The return value may be less than nbyte if the number of bytes remaining in the file is less than nbyte, if the read () request was interrupted by a signal, or if the file is a channel or FIFO or special file and has fewer than nbyte bytes that are immediately available for reading.

0
source share

I like this question. It makes me remember the old time ...

Meta response: it only knows if the stream is closed

Answer: your process reads everything that it can / should read, endlessly on "\ n"

But I suppose you want to write / read notes.

Despite others, I try to respond without distinguishing between the types of threads. I am making a disclaimer:

it all depends on the OS and the type of stream - and opening options on both sides (!)

Basic:

Suppose that one process writes another reading - quite simply.

No no.

Imagine - always ;-) - they put strings (bytes) there in the stream as they want, and they can - slowly - quickly - one by one or all of them are buffered.

and you read it - no - not you, not your program - between them - byte by byte or on block or how you like the layer between them.

So, if you want a recording, there are only three possibilities:

  • end char (byte) - block separator,
  • make the recording length fixed
  • old double byte length and then read the rest

Answer again:

in your case, the child puts all the characters in the stream that the parent reads, and above them - why does one of them take a break?

Decision:

Depending on the OS and language and libraries, you can sometimes specify the OS to make / accept the end of char (e.g. \ n) - sometimes your reading functions read this for you

0
source share

All Articles