### 主线程与子线程的结束顺序
主线程会等待所有的子线程执行结束再结束,除非设置子线程守护主线程。
```
import threading
import time
def work():
for i in range(10):
print("子线程工作中")
time.sleep(0.2)
if __name__ == '__main__':
sub_thread = threading.Thread(target=work)
sub_thread.start()
time.sleep(1)
print("主线程结束了")
```
演示效果:
```
子线程工作中
子线程工作中
子线程工作中
子线程工作中
子线程工作中
子线程工作中
子线程工作中
子线程工作中
子线程工作中
子线程工作中
主线程结束了
```
> 注意,`target=work`与`target=work()`的执行结果是不一致的。使用target=work()时,主线程会等待子线程执行完毕。
### 设置子线程守护主线程
#### 方法一
```
sub_thread = threading.Thread(target=work, daemon=True)
sub_thread.start()
```
#### 方法二
```
sub_thread = threading.Thread(target=work)
sub_thread.setDaemon(True)
sub_thread.start()
```
演示效果:
```
E:\PythonDevelop\zihan-python\06-basic>py 主线程和子线程的结束顺序.py
子线程工作中
子线程工作中
子线程工作中
子线程工作中
子线程工作中
主线程结束了
```
### 主动停止子线程
由于经常被Python非Daemon线程阻塞,导致程序无法结束。解决方案利用的是python内置API,通过ctypes模块调用,在线程中丢出异常,使线程退出。
```
def _async_raise(tid, exctype):
"""raises the exception, performs cleanup if needed"""
tid = ctypes.c_long(tid)
if not inspect.isclass(exctype):
exctype = type(exctype)
res = ctypes.pythonapi.PyThreadState_SetAsyncExc(tid, ctypes.py_object(exctype))
if res == 0:
raise ValueError("invalid thread id")
elif res != 1:
# """if it returns a number greater than one, you're in trouble,
# and you should call it again with exc=NULL to revert the effect"""
ctypes.pythonapi.PyThreadState_SetAsyncExc(tid, None)
raise SystemError("PyThreadState_SetAsyncExc failed")
def stop_thread(thread):
_async_raise(thread.ident, SystemExit)
def test():
while True:
print('-------')
time.sleep(0.5)
if __name__ == "__main__":
t = threading.Thread(target=test)
t.start()
time.sleep(5.2)
print("main thread sleep finish")
stop_thread(t)
```