16

I am trying to write a unix client program that is listening to a socket, stdin, and reading from file descriptors. I assign each of these tasks to an individual thread and have them successfully communicating with the "main" application using synchronized queues and a semaphore. The problem is that when I want to shutdown these child threads they are all blocking on input. Also, the threads cannot register signal handlers in the threads because in Python only the main thread of execution is allowed to do so.

Any suggestions?

Sisyphus
  • 4,181
  • 1
  • 22
  • 15
George
  • 161
  • 1
  • 1
  • 3
  • What kind of threads? There are a few libraries which provide threading functionality. – Blender Jun 15 '11 at 14:47
  • Unfortunately, this is just the tip of the iceberg when using separate (POSIX) threads for connections. Consider using non-blocking I/O instead (for example, using Twisted.) – Thomas Wouters Jun 15 '11 at 14:53
  • Threads need to terminate themselves (or be told to do so). can you make them not blocked, so they can exit if signaled? (polling or whatever) – Corey Goldberg Jun 15 '11 at 14:54
  • I am using the threading module, but have found similar difficulties in other threading utilities. – George Jun 15 '11 at 15:11

3 Answers3

9

There is no good way to work around this, especially when the thread is blocking.

I had a similar issue ( Python: How to terminate a blocking thread) and the only way I was able to stop my threads was to close the underlying connection. Which resulted in the thread that was blocking to raise and exception and then allowed me to check the stop flag and close.

Example code:

class Example(object):
   def __init__(self):
       self.stop = threading.Event()
       self.connection = Connection()
       self.mythread = Thread(target=self.dowork)
       self.mythread.start()     
   def dowork(self):

        while(not self.stop.is_set()):
             try:
                  blockingcall()        
             except CommunicationException:
                  pass
   def terminate():
       self.stop.set()
       self.connection.close()
       self.mythread.join()

Another thing to note is commonly blocking operations generally offer up a timeout. If you have that option I would consider using it. My last comment is that you could always set the thread to deamonic,

From the pydoc :

A thread can be flagged as a “daemon thread”. The significance of this flag is that the entire Python program exits when only daemon threads are left. The initial value is inherited from the creating thread. The flag can be set through the daemon property.

Community
  • 1
  • 1
Nix
  • 57,072
  • 29
  • 149
  • 198
  • 2
    Note that touching a filedescriptor that is being used by another thread is not safe, and it can cause much worse things than an exception in the other thread. You should really use non-blocking I/O instead. – Thomas Wouters Jun 15 '11 at 14:52
  • +1 I 100% agree, but there are some times when you can't... ;( – Nix Jun 15 '11 at 14:53
  • Unfortunately true, although rarely when it's filedescriptors you're operating on. (The truly problematic cases are blocking external libraries that have no way of interrupting operations at all :P) – Thomas Wouters Jun 15 '11 at 14:54
0

Also, the threads cannot register signal handlers

Signals to kill threads is potentially horrible, especially in C, especially if you allocate memory as part of the thread, since it won't be freed when that particular thread dies (as it belongs to the heap of the process). There is no garbage collection in C, so if that pointer goes out of scope, it's gone out of scope, the memory remains allocated. So just be careful with that one - only do it that way in C if you're going to actually kill all the threads and end the process so that the memory is handed back to the OS - adding and removing threads from a threadpool for example will give you a memory leak.

The problem is that when I want to shutdown these child threads they are all blocking on input.

Funnily enough I've been fighting with the same thing recently. The solution is literally don't make blocking calls without a timeout. So, for example, what you want ideally is:

def threadfunc(running):

    while running:
        blockingcall(timeout=1)

where running is passed from the controlling thread - I've never used threading but I have used multiprocessing and with this you actually need to pass an Event() object and check is_set(). But you asked for design patterns, that's the basic idea.

Then, when you want this thread to end, you run:

running.clear()
mythread.join()

and your main thread should then allow your client thread to handle its last call, and return, and the whole program folds up nicely.

What do you do if you have a blocking call without a timeout? Use the asynchronous option, and sleep (as in call whatever method you have to suspend the thread for a period of time so you're not spinning) if you need to. There's no other way around it.

-1

See these answers:

Python SocketServer
How to exit a multithreaded program?

Basically, don't block on recv() by using select() with a timeout to check for readability of the socket, and poll a quit flag when select() times out.

Community
  • 1
  • 1
Mark Tolonen
  • 166,664
  • 26
  • 169
  • 251
  • This is a decent solution, but I was hoping there was a more eloquent way to implement this without having to constantly loop. This would also cause a delay whenever I actually wanted to kill the thread while it waited for select to time-out. – George Jun 15 '11 at 15:15