如何用无限循环关闭所有线程? (使用_thread!别无其他!)

时间:2018-06-26 17:20:17

标签: python multithreading module

AggregateException

例如,在发生KeyboardInterrupts时如何停止两个线程? 因为对于“ KeyboardInterrupt除外”,线程仍在运行:/

重要: 问题是仅使用模块_thread关闭线程! 有可能吗?

1 个答案:

答案 0 :(得分:0)

除主线程外,无法直接与另一个线程进行交互。尽管某些平台确实提供了线程取消或杀死语义,但Python并没有公开它们,这是有充分理由的。 1

因此,通常的解决方案是使用某种信号告诉所有人退出。一种可能性是带有done的{​​{1}}标志:

Lock

当然,如果您使用done = False donelock = _thread.allocate_lock() def test1(): while True: try: donelock.acquire() if done: return finally: donelock.release() time.sleep(1) print('TEST1') _thread.start_new_thread(test1,()) time.sleep(3) try: donelock.acquire() done = True finally: donelock.release() (或Qt的线程之类的其他更高级别的API),同一件事会更清洁。另外,您可以使用threadingCondition使后台线程尽快退出,而不是仅在下一个Event完成之后退出。

sleep

done = threading.Event() def test1(): while True: if done.wait(1): return print('TEST1') t1 = threading.Thread(target=test1) t1.start() time.sleep(3) done.set() 模块当然没有_threadEvent,但是您始终可以自己构建一个,也可以只构建borrowing from the threading source


或者,如果您希望异步杀死线程(显然,如果线程正在写文件,那是不安全的,但是如果它们只是在进行计算或下载等无关紧要的操作, (如果您要取消,那很好)),Condition使其变得更加容易:

threading

请注意,您看到的行为实际上在跨平台上并不可靠:

  • 使用t1 = threading.Thread(target=test1, daemon=True) 创建的背景线程可能会继续运行,或者半干净地关闭,或者硬终止。因此,当您在便携式应用程序中使用_thread时,必须编写可处理这三个条件中的任何一个的代码。
  • _thread可以传递到任意线程而不是主线程。如果是这样,除非您已设置处理程序,否则它通常会杀死该线程。因此,如果您使用的是KeyboardInterrupt,通常需要处理_thread并调用KeyboardInterrupt

此外,我不认为您的_thread.interrupt_main()在做什么。 except:仅涵盖try个调用。如果线程成功启动,则主线程退出start_new_thread块并到达程序结尾。如果引发try或其他异常,则不会触发KeyboardInterrupt。 (此外,如果您想了解代码在做什么,则使用裸露的except:甚至不记录处理了哪个异常都是一个糟糕的主意。)大概在平台上,后台线程继续运行,和它们上的主线程块(可能是在OS级别,而不是Python级别,因此没有可以编写的代码参与其中)。

如果您希望主线程继续运行以确保它可以处理except:等问题(但请注意上面的注意事项!),则必须给它提供代码以继续运行:

KeyboardInterrupt

1。 Windows上的TerminateThread使得无法进行Python需要做的所有清理工作。 pthread_cancel可以在POSIX系统(例如Linux和macOS)上实现,但非常困难。两者之间的语义差异足够大,以致于试图编写跨平台的包装器将是一场噩梦。更不用说Python支持的系统(主要是较旧的Unix)没有完整的try: while True: time.sleep(1<<31) except KeyboardInterrupt: # background-thread-killing code goes here. API,甚至没有完全不同的线程API。