情况如下:
我正在使用WXWidgets编写一个简单的游戏。我的逻辑是游戏的主程序首先启动GUI,然后产生一个新的独立线程来实际运行游戏的逻辑。游戏逻辑顺序地,偶尔地(但不是非常频繁地)通过GUI接受来自用户的输入并用游戏数据更新GUI。游戏使用大量音频,因此GUI本身不会受到太多操作。
游戏线程经常做必须阻止的事情 - 这是适当的,因为这是一个游戏。 AI计算,从Internet加载数据等都会导致游戏线程被阻塞。这很好,因为游戏线程管理UI以确保用户无法在游戏线程可能无法响应的任何情况下操纵UI。
如果用户点击Alt + F4或Command-Q完全退出应用程序,则会出现问题。这会导致主GUI关闭,但它显然不会杀死游戏逻辑线程。游戏线程继续在后台运行,现在与UI断开连接,一旦它尝试与UI交互,它就会崩溃(正如在那种情况下预期的那样)。
我要做的是有一种方法向线程发出用户退出应用程序的信号 - 但是 - 不必乱丢我的代码,大量的“检查用户是否关闭了GUI”例程。首先,这个方法甚至不会一直有效,因为正如我所说的那样,游戏线程经常会在它做某事时阻塞,因此几秒钟就可以通过这样的调用永远不会被检查。
由于游戏线程是作为一个函数启动的,我想一个可能解决这个问题的好方法是,如果有一些方法让我在线程上引发自定义异常。然后我可以编写一个简单的包装函数将主游戏函数包装在try块中,特别是查找该异常。如果引发异常,我可以根据需要优雅地关闭套接字,关闭AI玩家等,然后优雅地退出线程。
有没有办法让这样的事情发生?
这是一个非常粗略的伪代码来说明问题:
目前:
def PlayGame(self):
# Get the game ready
self.initGame()
# Go into a loop to run the game
while (True):
# Get user's move
move = self.GUI_GetMove()
# Act based on the move
gameOver = self.processMove(move)
# If we got True, game is over.
if (gameOver == True): return
# Run the AI's logic - THIS MIGHT BLOCK AS THE AI PROCESSES AND/OR
# GRABS STUFF OFF THE INTERNET ETC.
move = self.AI_GetMove()
# Act based on the move
gameOver = self.processMove(move)
# (Let's pretend in this game the AI never ends the game)
continue
非常难看的方法:
def PlayGame(self):
# Get the game ready
self.initGame()
# Go into a loop to run the game
while (True):
# Get user's move
move = self.GUI_GetMove()
if (move == "EXIT" or self.GUI_Exited == True):
return
# Act based on the move
gameOver = self.processMove(move)
# If we got True, game is over.
if (gameOver == True): return
if (self.GUI_Exited == True):
return
# Run the AI's logic - THIS MIGHT BLOCK AS THE AI PROCESSES AND/OR
# GRABS STUFF OFF THE INTERNET ETC.
move = self.AI_GetMove()
# self.AI_GetMove might take 10 or more seconds - game will appear to
# be STUCK if user exits during an AI Process!
if (self.GUI_Exited == True):
return
# Act based on the move
gameOver = self.processMove(move)
if (self.GUI_Exited == True):
return
# (Let's pretend in this game the AI never ends the game)
continue
# That self.GUI_Exited code is duplicated SO many times - making
# this an awfully ugly and confusing block of code! In the real
# app, the check might need to be duplicated 100+ times!!!
我希望能够做到:
def PlayGame(self):
try:
self._PlayGame()
except UserExitedApplicationError:
self.AI.Stop()
self.sockets.closeAll()
return # return gracefully so thread exits
(记住很多不是真正的代码或功能 - 这只是让你知道我在想什么是一个很好的解决方案)
答案 0 :(得分:0)
请查看守护程序线程作为Python threading
库的一部分。默认情况下,线程是非守护进程,如果只有守护程序线程正在运行,Python将允许您退出。如果您在第一次创建后台游戏逻辑线程时将其指定为守护程序线程,则当您的主非守护程序线程退出时,该线程将自动被终止。
请注意,这只是最简单,最直接的方法,它有其缺点。线程将在释放任何资源之前被杀死。您还可以使用线程信令使该线程在停止之前首先释放其资源。最简单的线程信令形式是事件,也是threading
库的一部分。