0


Hi!
I have a C assignment where I need to make a named pipe (FIFO), and let 2 child processes write lines into it while the parent process reads those lines (and processes the received data). I'm new to this topic - fd locking, pipes, etc. - and I don't really understand the basic pipeline. Now I'm working with this structure:

  • program makes the pipe (mkfifo)
  • parent makes the 2 child processes (fork)
  • children write lines into pipe simultaneously while parent reads from the pipe, both following these steps on every iteration:
    • open file descriptor
    • write/read it
    • close file descriptor

It seems to me that somehow they get tangled and the parent process does not get all lines written into the pipe (at least when I don't make the children sleep so they don't work simultaneously).
Is there a neat way to lock the pipe after a write so that the other process can't access it, but the parent can for reading?

Thanks!

  • https://stackoverflow.com/questions/12111127/how-standard-specify-atomic-write-to-regular-filenot-pipe-or-fifo might be of interest to you. – Allan Wind May 15 '22 at 09:16
  • I think it would be better if you implement some simple example and show us what is your desired behavior. – complikator May 15 '22 at 10:41
  • Closing the pipe runs the risk of discarding information, especially if the parent process does it. OTOH, the parent has to close the FIFO if it gets EOF. Are the messages a fixed size? Can you do atomic reads and writes in the child processes, so a single call to `write()` (or perhaps `writev()`) sends the info to the parent? Are the messages small enough that there's no question of overflowing the pipe buffer with a single message? – Jonathan Leffler May 15 '22 at 12:00

1 Answers1

0

A FIFO server should not close() its FIFO; doing so is likely to lose data, and may also result in sending SIGPIPE to clients.

The server should open the FIFO for reading, and then read from it in a loop. Normally, it will attempt to create the FIFO first.

For a simple server, there's no need for locking or synchronisation; read() will block until there is data available. (Sometimes it is useful to avoid two servers simultaneously opening the same FIFO, but for most applications suitable for a named pipe, that should not be catastrophic.)

If the server is designed to be shut down (rather than just running until the system crashes for whatever reason), then it should close() the FIFO before exiting. (Of course, the operating system will do that anyway, but it's considered cleaner for the server to do it.) If the server is the only reader for the FIFO, closing it will signal SIGPIPE on any client which has the FIFO open and tries to write to it. By the same token, data in flight may be lost.

Clients can open and close FIFOs as they desire; the open-write-close loop you describe is a bit inefficient for frequent writes, but common for applications which write sporadically. The client should always check the return code from the write(), and it's usually a good idea to catch SIGPIPE to avoid sudden termination on server error.

Note that the whole point of named pipes is to allow unrelated processes to communicate (although they are really designed for one-way communication). So there's no need to fork children from the server process. If clients are always going to be children of the server, then anonymous pipes can be an easier interface.

rici
  • 234,347
  • 28
  • 237
  • 341