0

In the application I am developing I have a thread that when initialized starts a suprocess by Popen redirecting the stdout to PIPE. In the run() I need to wait both on the pipe and on an event.
The output of the pipe must be outputted on a textview.
When the event is set the thread must stop returning from the run().

My solution is to

  • wait on the pipe by a timeouted select.select
  • then if the select returns the pipe is readable
    • read a single byte from the pipe, so I am sure this reading can't block
    • store the byte in a bytearray up to I receive a newline
      • output the bytearray to a textviev
  • testing the event

This works but reading 1 byte per time is really inefficient
I am wondering it a more efficient solutions exists.

This is a snippet of my code:

class ProcessEcho(threading.Thread):

    def __init__(self,environ,command_line,textbuffer,on_process_exited_cb):
        super(ProcessEcho,self).__init__()

        self.textbuffer = textbuffer
        self.on_process_exited_cb = on_process_exited_cb

        self.popen = subprocess.Popen(command_line,stdout = subprocess.PIPE, stderr = subprocess.STDOUT,bufsize=0,env=environ)

        self.exit_event = threading.Event()

        self.daemon = True
        self.start()

    def get_pid(self):
        return self.popen.pid

    def stop(self):
        self.exit_event.set()

    def update_textbuffer(self,string):
        self.textbuffer.insert(self.textbuffer.get_end_iter(),string)

    def run(self):
        buffer = bytearray()
        while True:
            rl,wl,xl = select.select([self.popen.stdout], [], [], 1)

            if len(rl):
                r = self.popen.stdout.read(1)
                if r=='':
                    self.popen.communicate()
                    GObject.idle_add(self.on_process_exited_cb)
                    return
                else:
                    buffer.append(r)

                    if r == "\n":
                        GObject.idle_add(self.update_textbuffer,str(buffer))
                        buffer = bytearray()
            if self.exit_event.is_set():
                self.popen.communicate()
                GObject.idle_add(self.on_process_exited_cb)
                return
Irr
  • 656
  • 1
  • 9
  • 19

1 Answers1

0

To read a stream without blocking, use Queue.get_nowait()

Kim
  • 36
  • 2
  • How can I connect the Queue to the pipe?? – Irr Jan 22 '13 at 06:32
  • [This may help](http://stackoverflow.com/questions/375427/non-blocking-read-on-a-subprocess-pipe-in-python) – Kim Jan 22 '13 at 22:10
  • Excuse me, I didn't read carefully your answer: i don't want to read the pipe in non blocking mode, I want to block on pipe input being awakened by "data available on the pipe" or "setting of an event". I want to wait so the thread goes in kernel mode, otherwise if I read the pipe in non blocking mode, the thread is continuously in user mode and loads the cpu. – Irr Jan 24 '13 at 05:15
  • Then use "select" to wait until some data is available. – Kim Jan 25 '13 at 16:56