windows - Stopping the execution of threads in Python. The thread is blocked before join method -
i'm writing program execute child programs in new process , read stdout of these programs in separate thread , write in styledtextctrl
control. faced problem of stopping execution of threads. have following code:
import subprocess threading import thread, lock import wx import wx.stc import logging logging.basicconfig(level=logging.debug, format='[%(levelname)s] (%(threadname)-10s) %(module)10s:%(funcname)-15s %(message)s', ) class readthread(thread): def __init__(self, subp, fd, append_text_callback): thread.__init__(self) self.killed = false self.subp = subp self.fd = fd self.append_text_callback = append_text_callback def run(self): chunk = none while chunk != '' , not self.killed: self.subp.poll() chunk = self.fd.readline() if chunk: self.append_text_callback('%d: ' % self.subp.pid + chunk) if chunk == "": break logging.debug('end') class myform(wx.frame): def __init__(self): wx.frame.__init__(self, none, wx.id_any, "example1") panel = wx.panel(self, wx.id_any) self.log = wx.stc.styledtextctrl(panel, wx.id_any, size=(300,100), style=wx.te_multiline|wx.te_readonly|wx.hscroll) run_button = wx.button(panel, wx.id_any, 'run') self.bind(wx.evt_button, self.onrun, run_button) self.bind(wx.evt_close, self.oncloseframe) sizer = wx.boxsizer(wx.vertical) sizer.add(self.log, 1, wx.all|wx.expand, 5) sizer.add(run_button, 0, wx.all|wx.center, 5) panel.setsizer(sizer) self.read_thread_1 = none self.read_thread_2 = none self.log_lock = lock() def oncloseframe(self, event): logging.debug('close') if self.read_thread_1: self.read_thread_1.killed = true if self.read_thread_2: self.read_thread_2.killed = true if self.read_thread_1: self.read_thread_1.join(timeout=1) logging.debug('after 1 join') if self.read_thread_2: self.read_thread_2.join(timeout=1) logging.debug('after 2 join') self.read_thread_1 = none self.read_thread_2 = none event.skip() def onrun(self, event): cmd1 = "e:/threading_block/stdout_emulator.exe 50 500" subp1 = subprocess.popen(cmd1, stdout=subprocess.pipe, stderr=subprocess.pipe) self.read_thread_1 = readthread(subp1, subp1.stdout, self.appendtext) self.read_thread_1.start() cmd2 = "e:/threading_block/stdout_emulator.exe 21 400" sp2 = subprocess.popen(cmd2, stdout=subprocess.pipe, stderr=subprocess.pipe) self.read_thread_2 = readthread(sp2, sp2.stdout, self.appendtext) self.read_thread_2.start() logging.debug('end') def appendtext(self, text): self.log_lock.acquire() logging.debug('%s' % text) self.log.addtext(text) self.log_lock.release() if __name__ == "__main__": app = wx.pysimpleapp() frame = myform().show() app.mainloop()
i stop threads in oncloseframe
method. set killed
attribute in true
value , result cause finishing execution of while
loop in run
method of readthread
class. there no problem when close application (under windows) during execution of threads. if remove timeout=1
self.read_thread_1.join(timeout=1)
, self.read_thread_2.join(timeout=1)
there blocking of program.
the program stuck before self.read_thread_1.join()
in oncloseframe
method.
what's problem blocking? why should use timeout
join
?
the c code of std_emulator.exe following:
#include <stdio.h> #include <stdlib.h> #include <windows.h> #include <time.h> int main(int argc, char *argv[]) { int s; int n; if (argc > 1) { s = atoi(argv[1]); n = atoi(argv[2]); } else { s = 1; n = 50; } int i; (i = s; < n; ++i) { printf("this %d line\n", i); fflush(stdout); if (i % 2 == 0) { srand(time(null)); int r = rand() % 7; printf("sleep_type_2 %d\n", r); sleep(30 * r); fflush(stdout); } if (i % 3 == 0) { int r = rand() % 7; printf("sleep_type_3 %d\n", r); sleep(40 * r); fflush(stdout); } if (i % 5 == 0) { int r = rand() % 9; printf("sleep_type_5 %d\n", r); sleep(50); fflush(stdout); } } }
in case, you're not killing threads when use join(timeout=1)
. instead, join
operation waiting 1 second see if thread exits, , when doesn't, gives up. join
won't work because thread blocking on line:
chunk = self.fd.readline()
so it's never looping around see if killed
has been set true
. think best way cleanly shutdown threads terminate subprocess being run in readthread
in oncloseframe
:
if self.read_thread_1: self.read_thread_1.subp.terminate() self.read_thread_1.join() if self.read_thread_2: self.read_thread_2.subp.terminate() self.read_thread_2.join()
terminating subprocess unblock readline
call, , allow cleanly terminate thread.
Comments
Post a Comment