else: # in parent, listen to pipe
os.close(pipeout) # close output side here
pipein = os.fdopen(pipein) # make text mode input file object
while True:
line = pipein.readline()[:-1] # blocks until data sent
print('Parent %d got [%s] at %s' % (os.getpid(), line, time.time()))
parent()
This version has also been augmented to close the unused end of the pipe in each process
(e.g., after the fork, the parent process closes its copy of the output side of the pipe
written by the child); programs should close unused pipe ends in general. Running with
this new version reliably returns a single child message to the parent each time it reads
from the pipe, because they are separated with markers when written:
[C:\...\PP4E\System\Processes]$ python pipe2.py
Parent 8204 got [Spam 000] at 1267997789.33
Parent 8204 got [Spam 001] at 1267997790.03
Parent 8204 got [Spam 002] at 1267997792.05
Parent 8204 got [Spam 003] at 1267997795.06
Parent 8204 got [Spam 004] at 1267997799.07
Parent 8204 got [Spam 000] at 1267997799.07
Parent 8204 got [Spam 001] at 1267997800.08
Parent 8204 got [Spam 002] at 1267997802.09
Parent 8204 got [Spam 003] at 1267997805.1
Parent 8204 got [Spam 004] at 1267997809.11
Parent 8204 got [Spam 000] at 1267997809.11
Parent 8204 got [Spam 001] at 1267997810.13
...etc.: Ctrl-C to exit...
Notice that this version’s reads also return a text data str object now, per the default
r text mode for os.fdopen. As mentioned, pipes normally deal in binary byte strings
when their descriptors are used directly with os file tools, but wrapping in text-mode
files allows us to use str strings to represent text data instead of bytes. In this example,
bytes are decoded to str when read by the parent; using os.fdopen and text mode in
the child would allow us to avoid its manual encoding call, but the file object would
encode the str data anyhow (though the encoding is trivial for ASCII bytes like those
used here). As for simple files, the best mode for processing pipe data in is determined
by its nature.
Anonymous pipes and threads
Although the os.fork call required by the prior section’s examples isn’t available on
standard Windows Python, os.pipe is. Because threads all run in the same process and
share file descriptors (and global memory in general), this makes anonymous pipes
usable as a communication and synchronization device for threads, too. This is an
arguably lower-level mechanism than queues or shared names and objects, but it pro-
vides an additional IPC option for threads. Example 5-21, for instance, demonstrates
the same type of pipe-based communication occurring between threads instead of
processes.
Interprocess Communication | 227