Problem with threading and execv

Collapse
X
 
  • Time
  • Show
Clear All
new posts
  • Motoma
    Recognized Expert Specialist
    • Jan 2007
    • 3236

    Problem with threading and execv

    Hello everyone,

    I am having a tiny problem putting together a small script. I tried throwing together a multi-threaded ping utility, but the threads are not behaving the way I anticipated...P erhaps one of you could look and see why this is happening.

    Python 2.5.2, Ubuntu 8.04

    [code=python]
    #! /usr/bin/env python

    import os, sys, threading

    class PingThread(thre ading.Thread):
    host = ''

    def __init__(self, host):
    self.host = host
    threading.Threa d.__init__(self )

    def run (self):
    os.execv('/bin/ping', ['/bin/ping', self.host])

    print "PingThread('go ogle.com').star t()"
    PingThread('goo gle.com').start ()
    print "PingThread('ya hoo.com').start ()"
    PingThread('yah oo.com').start( )
    print "Main thread ended."
    [/code]

    If someone could point out my misuse of the Thread class, I would appreciate it.

    Thanks,
    Motoma
  • Motoma
    Recognized Expert Specialist
    • Jan 2007
    • 3236

    #2
    It appears that my problem is not with the utilization of the Thread class; rather, my error was with my misunderstandin g of the way python's exec*() functions work.

    In C, one way to spawn a new process is to fork() and exec*() in the new thread. However, when running exec*() commands in python, it appears that the entire python process is taken over by the exec*() command, not just that particular thread. My solution to this issue is to utilize the os.system() call, rather than the os.exec*() call.

    Working example:

    [code=python]
    #! /usr/bin/env python

    import os, sys, threading

    class PingThread(thre ading.Thread):
    host = ''

    def __init__(self, host):
    self.host = host
    threading.Threa d.__init__(self )

    def run(self):
    os.system('/bin/ping %s' %(self.host))

    print "PingThread('go ogle.com').star t()"
    PingThread('goo gle.com').start ()
    print "PingThread('ya hoo.com').start ()"
    PingThread('yah oo.com').start( )
    print "Main thread ended."
    [/code]

    Comment

    • weazzle
      New Member
      • Sep 2008
      • 1

      #3
      Originally posted by Motoma
      It appears that my problem is not with the utilization of the Thread class; rather, my error was with my misunderstandin g of the way python's exec*() functions work.

      In C, one way to spawn a new process is to fork() and exec*() in the new thread. However, when running exec*() commands in python, it appears that the entire python process is taken over by the exec*() command, not just that particular thread. My solution to this issue is to utilize the os.system() call, rather than the os.exec*() call.
      [/code]
      Actually, these work the same in both C and Python. You are confusing threads and processes. The fork() system call creates a new process, you then must determine which process is the child, and explicitly replace the current program using one of the exec* functions. If you simply launch a new thread, the thread is running as part of the same process, so it will naturally take over the entire process when you call an exec* function. The important thing to understand here is that a Thread is a different construct than a process.

      The os.system() call is nice and easy, however, if you want to set up special inter-process communication, you should really be using the fork(), exec*() and potentially dup2(). dup2() allows you to map a file descriptor to another. For example, if you want the new process to read from the parent process instead of stdin, you need to remap its stdin file descriptor to a pipe from the parent process using dup2() before launching the program.

      Example (grep data in parent):

      Code:
      #include os
      #include sys
      
      (pipe_read, pipe_write) = os.pipe()
      
      pid = os.fork()
      if pid: #parent process
          os.close( pipe_write )
          os.dup2( pipe_read, sys.stdin.fileno() )
          os.execv('/bin/grep', ['/bin/grep', expression])
      else: #parent process
          os.close( pipe_read )
          os.write( pipe_write, text )
      The above example is not complete, you would need a way to retrieve the data from the child process, potentially via another pipe that redirects its stdout.

      Comment

      Working...