### 主線程與子線程的結束順序
主線程會等待所有的子線程執行結束再結束,除非設置子線程守護主線程。
```
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)
```