关闭主线程时如何合理关闭子线程

picked from :http://blog.sina.com.cn/s/blog_3c8ced5801014pbv.html
昨天为我的 casnet 程序添加新功能。其中一个功能是断线自动重连,本来是单线程的程序,添加这个功能就需要后台有一个线程定时地查询当前状态,如果掉线就自动重连。因之遇到了一个如何设计这个守护线程的问题。

我刚开始的想法是后台线程每次运行查询后 sleep 一段时间,然后再运行查询。但是我马上遇到了一个问题:当主程序退出时,后台线程仍在运行,主窗口无法退出。

在使用其它的库时,比如 POSIX 的 pthread,可以使用 ptread_cancel(tid) 在主线程中结束子线程。但是 Python 的线程库不支持这样做,理由是我们不应该强制地结束一个线程,这样会带来很多隐患,应该让该线程自己结束自己。所以在 Python 中,推荐的一种方法是在子线程中循环判断一个标志位,在主线程中改变该标志位,子线程读到标志位改变,就结束自己。

import threading

class X(threading.Thread):
def __init__(self):
threading.Thread.__init__(self)
self.flag = 1

def run(self):
while self.flag == 1:
sleep(300)
...

如果直接使用这种方法,那么我前面的设计就会出现问题。因为线程会被 sleep 阻塞一段时间,那么只有在 sleep 的间隙,才有可能去读取标志位。这样主线程需要等待当前 sleep 结束才能使子线程退出,进而整个程序才能退出。这种做法是行不通的,你不可能指望用户点击“关闭窗口”后等待几百秒程序才能退出。

当然,也可以使用系统命令 kill 来杀死整个进程。但问题是这样做既不 graceful,又不能保证代码对不同系统的兼容性。

再深入思考一下,虽然本文中的后台线程从功能上来看似乎用不着考虑太多同步的问题,但最后的退出过程可视为一个线程同步的过程。因此可以采用线程同步的思想来设计后台线程:在正常工作时,后台线程进行带超时的等待,超时后就执行工作;退出时主线程给后台线程发送一个信号,由于后台线程在超时等待,因此接收信号后就终止退出。这样,在用户结束程序时,就不用等待 sleep 到时了。

import threading

class X(threading.Thread):
def __init__(self):
threading.Thread.__init__(self)
self.flag = 1
self.cond = threading.Condition()

def run(self):
self.cond.acquire()
self.condition.wait(300)
while self.flag == 1:
...
self.cond.release()
self.cond.acquire()
self.condition.wait(300)

...
x.flag = 0
x.cond.acquire()
x.cond.notify()
x.cond.release()

 
pt

python 2.6 里,用 subprocess 生成子进程,可以被杀死

Popen.kill()¶

Kills the child. On Posix OSs the function sends SIGKILL to the child. On Windows kill() is an alias for terminate().

 

 

posted on 2013-11-12 17:02  JohnChain  阅读(3076)  评论(0编辑  收藏  举报

导航