Jack
Jack

Reputation: 393

Kill Subprocess in Python after timeout

I searchedon internet and learned other method of implementing it the problem now i have found out. my execution time always becomes more than that of time out if i write stdout=subprocess.PIPE in subprocess.Popen. If i am removing it then it is taking normal execution time

import subprocess, datetime, os, time, signal
//setting time for timeout
timeout=3
start = datetime.datetime.now()
process = subprocess.Popen(["python", "/home/bourne/untitled.py"],shell=False, stdout=subprocess.PIPE,stderr=subprocess.PIPE)
while process.poll() is None:
        time.sleep(0.1)
        now = datetime.datetime.now()
        if (now - start).seconds > timeout:
            os.kill(process.pid, signal.SIGKILL)
            os.waitpid(-1, os.WNOHANG)
            print "error"       
            print (now - start).seconds
            break
        print (now - start).seconds

Upvotes: 2

Views: 3879

Answers (3)

Jack
Jack

Reputation: 393

I have successfully solved the problem. the solution is 

import subprocess, signal, os, threading, errno
from contextlib import contextmanager

class TimeoutThread(object):
    def __init__(self, seconds):
        self.seconds = seconds
        self.cond = threading.Condition()
        self.cancelled = False
        self.thread = threading.Thread(target=self._wait)

    def run(self):
        """Begin the timeout."""
        self.thread.start()

    def _wait(self):
        with self.cond:
            self.cond.wait(self.seconds)

            if not self.cancelled:
                self.timed_out()

    def cancel(self):
        """Cancel the timeout, if it hasn't yet occured."""
        with self.cond:
            self.cancelled = True
            self.cond.notify()
        self.thread.join()

    def timed_out(self):
        """The timeout has expired."""
        raise NotImplementedError

class KillProcessThread(TimeoutThread):
    def __init__(self, seconds, pid):
        super(KillProcessThread, self).__init__(seconds)
        self.pid = pid

    def timed_out(self):
        try:
            os.kill(self.pid, signal.SIGKILL) // this is for linux you need to change it for windows
        except OSError,e:
            # If the process is already gone, ignore the error.
            if e.errno not in (errno.EPERM, errno. ESRCH):
                raise e

@contextmanager
def processTimeout(seconds, pid):
    timeout = KillProcessThread(seconds, pid)
    timeout.run()
    try:
        yield
    finally:
        timeout.cancel()


def example(cmd):
    proc = subprocess.Popen(cmd, stderr=subprocess.PIPE, stdout=subprocess.PIPE)
    //setting the timeout to be 1 sec
    with processTimeout(1, proc.pid):
        stdout,stderr=proc.communicate()       

    resultcode = proc.wait()
    if resultcode < 0:
        #print "error: %i" % resultcode
        return resultcode,0
    else:
        return stdout,stderr





//This is used to create new subprocess and it will return output as well as error
output,err=example(["python",filepath,"5"])

Upvotes: 1

fanlix
fanlix

Reputation: 1378

Thread can be handled in python VM, but process not. so u have to use OS api to kill ur process/subprocess, such as (in linux):

os.system("kill -9 %s"%(proc.pid))

and, using thread for timing is a bad idea. how about:

start_t = time.time()
TIME_END, TIME_SLEEP = 5, 1
while time.time() - start_t < TIME_END:
    if proc.poll():
        break
    time.sleep(TIME_SLEEP)

Upvotes: 0

mata
mata

Reputation: 69082

You shouldn't spawn a new thread just for having it time out in 5 seconds and then use it's isAlive status as break condition for a busy wait. You don't need an extra thread for that, you can messure the time in the first thread.

Instead of polling the thread as often as you can, you should use a delay (time.sleep) to allow the processor to do some real work.

And you should know that if your process is generating a lot of output, it will block if you don't read it while the process is executing and let it fill up the pipe's buffer.

Upvotes: 3

Related Questions