Reputation: 21
Is it possible to use one pipe for both writing and reading between processes? My pseudocode is pretty much like below. I tried but it gave me an error said "bad file descriptor".
create fd[2]
create pipe(fd)
parent:
close fd[0]
write something to fd[1]
close fd[1]
// wait for child's signal
close fd[1]
read the response fd[0]
close fd[0]
child:
close fd[1]
read the pipe fd[0]
close fd[0]
// write an answer to the parent via the existing pipe
// no need to close fd[0], since it's already closed
write the answer fd[1]
close fd[1]
signal to the parent
Thanks a lot in advance.
Upvotes: 2
Views: 1776
Reputation: 180201
Is it possible to use one pipe for both writing and reading between processes?
Technically, yes, it is possible for two processes to use a single pipe for bidirectional communication. There are no special requirements of the pipe itself to enable this, but each process must leave each pipe end open as long as they want to use that end (contrary to your pseudocode). To be clear, though: pipes have a write end and a read end. All writes to a pipe must go to the write end, and all reads must be performed on the read end, but multiple processes can use each end.
But it is extremely tricky to make the actual bidirectional communication work correctly that way, because any data written to a pipe can be read by any process that has the read end open, including the one that wrote it (though only one will actually read each byte), and because no process will observe an end-of-file signal on the read end of the pipe as long as any process has the write end open. Thus, to use a single pipe bidirectionally, you need some additional IPC mechanism to mediate among the communicating processes to ensure that each one receives complete messages, that messages do not become comingled, and, if applicable, that each process receives only the messages directed to it.
It is much easier to just set up two pipes for each pair of communicating processes, one for each direction.
Upvotes: 2
Reputation: 16850
When you close a file descriptor, you cannot use it anymore.
A pipe is unidirectional; in many applications, you just decide
between your two processes which one will be the reader and which
one will be the writer.
But with a specific synchronisation, you can swap these two roles
as suggested in your example (see the edit below).
If you need a bidirectional stream, you could usesocketpair(PF_LOCAL, SOCK_STREAM, 0, fd)
.
edit, about closing not too early
Just close an end of a pipe when you are certain that
your process won't need it any more.
Just don't expect to detect the end-of-file before the synchronisation signal because the other end of the pipe is not closed yet.
This example could help.
#!/usr/bin/env python
import sys
import os
import signal
fd=os.pipe()
p=os.fork()
if p==0:
signal.signal(signal.SIGUSR1, lambda signum, frame: 0)
os.write(fd[1], b'A')
os.close(fd[1]) # I will never write again to this pipe
signal.pause() # wait for the signal before trying to read
b=os.read(fd[0], 1)
os.close(fd[0]) # I will never read again from this pipe
sys.stdout.write('child got <%s>\n'%b)
else:
a=os.read(fd[0], 1)
os.close(fd[0]) # I will never read again from this pipe
sys.stdout.write('parent got <%s>\n'%a)
os.kill(p, signal.SIGUSR1) # now the child is allowed to read
os.write(fd[1], b'B')
os.close(fd[1]) # I will never write again to this pipe
os.wait()
Upvotes: 2