无论如何从线程终止正在运行的函数?

时间:2015-05-24 15:32:16

标签: python multithreading

我最近尝试在python中编写自己的Socket-Server。 当我编写一个线程来处理服务器命令(服务器中的命令行)时,我试图实现一个代码,当raw_input()收到特定命令时将重启服务器。

基本上,我希望在“Running”变量将其状态从True更改为False后立即重新启动服务器,并且当它执行时,我想停止运行的函数(调用线程的函数)(返回主函数)然后再次运行它。有办法吗?

非常感谢,我希望我能清楚我的问题,

Idan:)

3 个答案:

答案 0 :(得分:0)

线程之间的通信可以通过EventQueueSemaphore等完成。检查出来并选择最符合您问题的那个。

答案 1 :(得分:0)

据我所知,文档和我过去几周的一些实验,没有办法真正强迫另一个线程“停止”或“中止”。除非该功能意识到被停止的可能性并且具有避免陷入某些I / O功能的万无一失的方法。然后你可以使用一些通信方法,如信号量。唯一的例外是专门的Timer函数,它有一个Cancel方法。

所以,如果你真的想强行停止服务器线程,你可能想要考虑在一个单独的进程中运行它,而不是一个线程。

编辑:我不确定你为什么要重新启动服务器 - 我只是认为这是在失败的情况下。服务器中的正常过程是循环等待套接字上的连接,当出现连接时,请参加它并返回到该循环。

更好的方法是使用GIO libraryglib的一部分),并将方法连接到连接事件,甚至异步地参加连接。这完全避免了循环。我在Python中没有任何真正的代码,但Python中的客户端here's an example(使用GIO进行接收事件)和C中使用GIO进行连接的服务器。

使用GIO让生活如此更容易......

答案 2 :(得分:0)

您无法在Python中中止线程或异步引发异常。

此问题的标准Unix解决方案是使用非阻塞套接字,使用pipe创建管道,用阻塞sock.recv替换所有阻止r, _, _ = select.select([sock, pipe], [], [])调用,然后另一个线程可以写入管道唤醒另一个线程。

为了使这个可移植到Windows,您需要创建一个UDP localhost套接字而不是管道,这会使事情稍微复杂一些,但它仍然不难。

或者,当然,您可以使用更高级别的框架,例如3.4+中的asyncio,或twisted或其他第三方lib,它们将为您提供此功能。 (他们中的大多数已经在select周围运行相当于一个循环来为一个线程或一个小线程池中的大量客户端提供服务,因此在停止管道中投入很少。)

还有其他选择吗?是的,但是在各种其他方面都不那么便携而且不太好。

大多数平台都有办法异步终止或发信号通知另一个线程,你可以通过它来访问,例如ctypes。但这是一个坏主意,因为它会阻止Python进行任何正常的清理。即使你没有得到段错误,这可能意味着文件永远不会被刷新并最终得到不完整的/垃圾数据,锁被留下来使你的程序在短时间内完全无关,内存被泄露等等。

如果您特意尝试中断主线程,并且只关心Unix上的CPython,则可以使用signal处理程序和kill函数。该信号将在下一个Python字节码上生效,如果解释器被阻塞在任何类型的I / O(或大多数其他系统调用,例如,在sleep内),系统将返回到解释器EINTR,允许它立即中断。如果解释器被阻塞在其他东西上,比如调用阻止信号的C库或者除了CPU工作30秒之外什么都不做,那么你将不得不等待30秒(尽管那并不是经常这样,你应该知道它是否会在你的情况下)。此外,线程和信号在一些较旧的* nix平台上不能很好地发挥作用。并且信号在Windows或其他一些Python实现(如Jython)中的工作方式不同。

在某些平台上(包括Windows - 但不是大多数现代* nix plafforms),只需从等待线程下关闭套接字就可以唤醒阻塞套接字调用。在其他平台上,这不会解锁线程,或者有时会这样做但不会在其他时间执行(理论上它甚至可能会使程序出现段错误或使套接字库处于无法使用的状态,尽管我不会想到其中任何一个将在任何现代平台上发生。)