Help | Site Map
Connecting Tech Pros Worldwide
Reply
 
LinkBack Thread Tools
  #1  
Old September 8th, 2008, 04:13 PM
Motoma's Avatar
Site Moderator
 
Join Date: Jan 2007
Location: Maine, USA
Age: 25
Posts: 2,896
Default 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...Perhaps one of you could look and see why this is happening.

Python 2.5.2, Ubuntu 8.04

Expand|Select|Wrap|Line Numbers
  1. #! /usr/bin/env python                                                               
  2.  
  3. import os, sys, threading
  4.  
  5. class PingThread(threading.Thread):
  6.     host = ''
  7.  
  8.     def __init__(self, host):
  9.         self.host = host
  10.         threading.Thread.__init__(self)
  11.  
  12.     def run (self):
  13.         os.execv('/bin/ping', ['/bin/ping', self.host])
  14.  
  15. print "PingThread('google.com').start()"
  16. PingThread('google.com').start()
  17. print "PingThread('yahoo.com').start()"
  18. PingThread('yahoo.com').start()
  19. print "Main thread ended."
  20.  
If someone could point out my misuse of the Thread class, I would appreciate it.

Thanks,
Motoma
Reply
  #2  
Old September 8th, 2008, 04:27 PM
Motoma's Avatar
Site Moderator
 
Join Date: Jan 2007
Location: Maine, USA
Age: 25
Posts: 2,896
Default

It appears that my problem is not with the utilization of the Thread class; rather, my error was with my misunderstanding 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:

Expand|Select|Wrap|Line Numbers
  1. #! /usr/bin/env python                                                               
  2.  
  3. import os, sys, threading
  4.  
  5. class PingThread(threading.Thread):
  6.     host = ''
  7.  
  8.     def __init__(self, host):
  9.         self.host = host
  10.         threading.Thread.__init__(self)
  11.  
  12.     def run(self):
  13.         os.system('/bin/ping %s' %(self.host))
  14.  
  15. print "PingThread('google.com').start()"
  16. PingThread('google.com').start()
  17. print "PingThread('yahoo.com').start()"
  18. PingThread('yahoo.com').start()
  19. print "Main thread ended."
  20.  
Reply
  #3  
Old September 18th, 2008, 04:57 PM
Newbie
 
Join Date: Sep 2008
Posts: 1
Default

Quote:
Originally Posted by Motoma
It appears that my problem is not with the utilization of the Thread class; rather, my error was with my misunderstanding 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):

Expand|Select|Wrap|Line Numbers
  1. #include os
  2. #include sys
  3.  
  4. (pipe_read, pipe_write) = os.pipe()
  5.  
  6. pid = os.fork()
  7. if pid: #parent process
  8.     os.close( pipe_write )
  9.     os.dup2( pipe_read, sys.stdin.fileno() )
  10.     os.execv('/bin/grep', ['/bin/grep', expression])
  11. else: #parent process
  12.     os.close( pipe_read )
  13.     os.write( pipe_write, text )
  14.  
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.
Reply
Reply

Bookmarks

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are Off
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are On

What is Bytes?

We are a network of experts and professionals in IT and software development that help one another with answers to tough questions and share insights. Get the best answers to your questions from over network members.
Post your question now . . .
It's fast and it's free

Popular Articles