problems with blocking pipes, threading

Sven Drescher Sven.Drescher at dlr.de
Fri Jan 28 05:28:08 EST 2000


Hallo,

I'm on the way to implement a process manager to start and finish specific
processes. I do that with fork and execv under Solaris and with Mark
Hammond's win32 extensions under Windows NT. All starts and finishs correct.
But if I try to redirect the childs stdout with a pipe and read it out
parallel from parent, the read-function blocks until the child is killed.
Here is a short example of my test programm. I don't know what's wrong. I
tried two threads, but still blocking.

The threading modul seems also to be not correct. Threads on my Sun don't
work parallel. Has anybody also such problems or a solution?

The example programm is ones from Mark Hammond's example. I modified it.
The command is only a little program which does a few outputs and delays.

Thanks for hints and help. Can it be, that an other way is more effective
for my problem???

Sven

example:
'''runproc.py

start a process with three inherited pipes.
Try to write to and read from those.
'''

import win32api
import win32pipe
import win32file
import win32process
import win32security
import win32con
import msvcrt
import os

import threading

class Process:
    def run(self, cmdline):
        # security attributes for pipes
        sAttrs = win32security.SECURITY_ATTRIBUTES()
        sAttrs.bInheritHandle = 1

         self.cmdline=cmdline

        # create pipes
        self.hStdout_r, self.hStdout_w = win32pipe.CreatePipe(sAttrs, 0)

        # set the info structure for the new process.
        self.StartupInfo = win32process.STARTUPINFO()
        self.StartupInfo.hStdOutput = self.hStdout_w
        self.StartupInfo.dwFlags = win32process.STARTF_USESTDHANDLES

        # Create new output read handles and the input write handle. Set
        # the inheritance properties to FALSE. Otherwise, the child inherits
        # the these handles; resulting in non-closeable handles to the pipes
        # being created.
        pid = win32api.GetCurrentProcess()

        tmp = win32api.DuplicateHandle(
            pid,
            self.hStdout_r,
            pid,
            0,
            0,     # non-inheritable!
            win32con.DUPLICATE_SAME_ACCESS)
        # Close the inhertible version of the handle
        win32file.CloseHandle(self.hStdout_r)
        self.hStdout_r = tmp

        self.stdout = os.fdopen(msvcrt.open_osfhandle(self.hStdout_r, 0),
"rb", 0)
        threading.Thread(None, self.ausgabe).start()
        threading.Thread(None, self.start).start()

    def start(self):
        # start the process.
        hProcess, hThread, dwPid, dwTid = win32process.CreateProcess(
                None,   # program
                self.cmdline,# command line
                None,   # process security attributes
                None,   # thread attributes
                1,      # inherit handles, or USESTDHANDLES won't work.
                        # creation flags. Don't access the console.
                0,      # Don't need anything here.
                        # If you're in a GUI app, you should use
                        # CREATE_NEW_CONSOLE here, or any subprocesses
                        # might fall victim to the problem described in:
                        # KB article: Q156755, cmd.exe requires
                        # an NT console in order to perform redirection..
                None,   # no new environment
                None,   # current directory (stay where we are)
                self.StartupInfo)
        # normally, we would save the pid etc. here...

        # Child is launched. Close the parents copy of those pipe handles
        # that only the child should have open.
        # You need to make sure that no handles to the write end of the
        # output pipe are maintained in this process or else the pipe will
        # not close when the child process exits and the ReadFile will hang.
        win32file.CloseHandle(self.hStdout_w)

    def ausgabe(self):
        import select
        while 1:
              try:
                  #select.select([self.stdout.fileno()], [], [])
                   print "Read on stdout: ", self.stdout.read(1)
               except:
                   print 'error'

if __name__ == '__main__':
    p = Process()
    exe = win32api.GetModuleFileName(0)
    p.run(exe + ' run_task.py')

# end of runproc.py


--
______________________________________
German Aerospace Research Establishment
e-mail: Sven.Drescher at dlr.de






More information about the Python-list mailing list