error using pipes in python using os.pipe() and using os.fork()

Question:

So I made a simple piece of code to add 1 to a value. I create two process and I am creating a pipe for storage the information beetween iterations. In the first cycle it gives the correct value but in the second iterration it gives two errors.
My code:

def processMain():
    number = 0
    r, w = os.pipe()

    for _ in range(2):
        pid = os.fork()
        if pid == 0:
            number = int(number)
            number += 1
            number = str(number)

            os.close(r)
            w = os.fdopen(w, "w")
            w.write(number)
            print("write")
            sys.exit(0)

        else:
            os.wait()

            os.close(w)
            r = os.fdopen(r)
            number = r.read()
            print("read")
    print(number)

I excute the function and it gives me this results:

write
read
Traceback (most recent call last):
  File "/home/aluno-di/area-de-aluno/SO/projeto/grupoXX/tests.py", line 31, in <module>
    processMain()
  File "/home/aluno-di/area-de-aluno/SO/projeto/grupoXX/tests.py", line 15, in processMain
    os.close(r)
TypeError: '_io.TextIOWrapper' object cannot be interpreted as an integer
Traceback (most recent call last):
  File "/home/aluno-di/area-de-aluno/SO/projeto/grupoXX/tests.py", line 31, in <module>
    processMain()
  File "/home/aluno-di/area-de-aluno/SO/projeto/grupoXX/tests.py", line 24, in processMain
    os.close(w)
OSError: [Errno 9] Bad file descriptor

I don’t understand what I am doing wrong or what I am not doing that I need to do to this work.

Asked By: Duarte GV

||

Answers:

Re-assigning r = os.fdopen(r) is problematic here because the return value of os.fdopen is a TextIOWrapper, while the functions that use r require the value to be an integer. The first time you run the loop it works just fine because r is assigned to the first return from os.pipe(), however, then on it’s converted to the TextIOWrapper where it will fail for both os.fdopen() and os.close()

Also, depending on the return value of r.read(), it’s possible to get a None value, causing the program to fail when you try to run number = int(number)

Answered By: Jamie.Sgro

This should work. Note that number needs to be a shared memory value if you want the incrementing done by the child process reflected in the main process:

import os
from multiprocessing import Value, Pipe
import sys

def processMain():
    number = Value('i', 0)
    r, w = Pipe(duplex=False)

    for _ in range(2):
        pid = os.fork()
        if pid == 0:
            number.value += 1
            n = number.value
            w.send(n)
            sys.exit(0)
        else:
            n = r.recv()
            print("read", n)
            os.waitid(os.P_PID, pid, os.WEXITED)

processMain()

Prints:

read 1
read 2
Answered By: Booboo
Categories: questions Tags: , , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.