d3im
d3im

Reputation: 413

kill python thread while it waits for read for a long time

I need to terminate thread but can't check regularly any flags since it waits for reading/input.

Simple example:

import threading, time

class Test(threading.Thread):
    def __init__(self):
        threading.Thread.__init__(self)

    def run(self):
        print(input("wainting for input: "))

th = Test()
th.start()
time.sleep(5)
print("killing!")
th.join(5)
print(th.is_alive())

The more real example is this (kill thread when it hangs - no output for longer time):

import threading, time

class Test(threading.Thread):
    def __init__(self):
        threading.Thread.__init__(self)

    def call(args):
        return subprocess.Popen(" ".join(args), shell=True, stderr=subprocess.PIPE)     

    def run(self):
        mainProcess = call([ any program that could hang])
        out = None
        while mainProcess.returncode != 0 or out == '' and mainProcess.poll() != None:
            out = mainProcess.stderr.read(1)
            if out != '':
                sys.stdout.write(out)
                sys.stdout.flush()

th = Test()
th.start()
time.sleep(5)
print("killing!")
th.join(5)
print(th.is_alive())

If there is a better approach, I would be happy too.

Upvotes: 0

Views: 400

Answers (2)

Daniel
Daniel

Reputation: 42768

Here's an example, how you can solve your hanging process problem with select:

import threading
import select
import subprocess
import sys

def watch_output(args, timeout):
    process = subprocess.Popen(args, stdout=subprocess.PIPE)     
    while True:
        ready_to_read, _, _ = select.select([process.stdout], [], [], timeout)
        if not ready_to_read:
            print "hanging process"
            process.kill()
            break
        out = ready_to_read[0].read(1)
        if not out:
            print "normal exit"
            break
        sys.stdout.write(out)
        sys.stdout.flush()
    return process.wait()

watch_output(['ls'], timeout=10)

or even your input with timeout is possible:

def read_input(prompt, timeout):
    sys.stdout.write(prompt)
    sys.stdout.flush()
    ready_to_read, _, _ = select.select([sys.stdin], [], [], timeout)
    if not ready_to_read:
        return None
    return ready_to_read[0].readline()

print read_input("wainting for input (4s): ", 4)

Upvotes: 1

ErikR
ErikR

Reputation: 52049

You can just have the main thread kill the process. The reader thread will eventually hit EOF and then exit.

Example:

#!/usr/bin/env python

import threading
import subprocess
import time
import sys

def pipe_thread(handle):
  print "in pipe_thread"
  x = handle.readline()
  while x:
    print "got:", x[:-1]
    x = handle.readline()

def main():
  p = subprocess.Popen(["./sender"], stdout = subprocess.PIPE)
  t = threading.Thread(target = pipe_thread, args = [p.stdout])
  t.start()

  print "sleeping for a while"
  time.sleep(5)
  print "killing process"
  p.kill()
  print "joining"
  t.join()
  print "joined"

main()

Upvotes: 0

Related Questions