使用KeyboardInterrupt关闭多线程应用程序



我有一个有两个线程的应用程序。一个是pygame线程,它运行一个简单的游戏,另一个线程是一个监听服务器,它接受用于控制游戏的消息。

下面是剥离后的伪代码:

class ServerThread(threading.Thread):
    def run(self):
        class SingleTCPHandler(SocketServer.BaseRequestHandler):
            try:
                while(1):
                ...
                #Receive messages from socket. Add them to pygame event queue
                ...
            except KeyboardInterrupt:
                sys.exit(0)
...
...
class PygameThread(threading.Thread):
    def run(self):
    ...
    #pygame stuff
    ...
    #The following pygame code closed the app when closing the pygame window while running as a single thread
        for event in pygame.event.get():
                if event.type==QUIT:
                    exit()
   ...
try:
    server_thread = ServerThread()
    server_thread.start()
    pygame_thread = PygameThread()
    pygame_thread.start()
except KeyboardInterrupt:
    sys.exit(0)

似乎没有捕获任何异常。我试过只运行服务器没有pygame线程和:

        try:
            while(1):
            ...
            #Receive messages from socket. Add them to pygame event queue
            ...
        except KeyboardInterrupt:
            sys.exit(0)

Ctrl + c无反应

pygame窗口标准关闭按钮(小x op右)不再工作。

和我尝试的变通方法:

try:
    server_thread = ServerThread()
    server_thread.start()
    pygame_thread = PygameThread()
    pygame_thread.start()
except KeyboardInterrupt:
    sys.exit(0)

也不能工作。

我正在寻找关闭应用程序而不必杀死应用程序已启动的外壳的想法。

根据这个建议,我做了以下的事情: 将两个踏面的前while True改为while not self.stop_requested:

也:

try:
    pygame_thread = PygameThread()
    pygame_thread.start()
    server_thread = ServerThread()
    server_thread.start()
except KeyboardInterrupt:
    pygame_thread.stop_requested = True
    server_thread.stop_requested = True

它仍然不工作。我还注意到,在运行这段代码的控制台中,当我尝试用Ctrl+c终止时,它只被打印出来。

alan@alan ~/.../py $ python main.py 
^C^C^C^C^C^C^C

我做了一个小快捷方式,并将服务器线程更改为daemon,因此一旦pygame窗口(即pygame线程)关闭,它就会关闭。

在主程序的except块中,您应该以某种方式通知Thread s自行停止。你可以看看我在这个帖子里的回答,了解我的意思。

基本上,用while not self.stop_requested:循环代替while(1):循环。然后,您可以在主线程内部设置类的这个字段,在这里实际捕获KeyboardInterrupt。然后你还应该从主线程中join()每个线程,然后你就知道一切都停止了。

顺便说一句:我不会使用while(1)while True更直观,因为每次循环迭代时,1都被计算为bool。为什么不在预期的地方写一个bool呢?括号也是多余的。这种符号可以追溯到古老的C语言,它没有布尔类型。

sys.exit是一个有点令人困惑的名字,因为它实际上并没有终止或"退出"任何东西。它只抛出一个异常,如果在一个线程中这样做,异常仍然是该线程的局部异常。要在主上下文中抛出SystemExit,您将需要thread.interrupt_main

最新更新