gpt4 book ai didi

python 应用程序在 thread.join() 上卡住

转载 作者:行者123 更新时间:2023-12-03 12:47:41 29 4
gpt4 key购买 nike

我正在用 Python3 和 PyQt5 编写一个简单的时间跟踪应用程序。在单独的线程中跟踪时间。该线程正在运行的函数不访问 GUI 代码。在 Windows10 上,应用程序在尝试关闭后卡住。它是由调用 thread.join() 引起的。我需要在任务管理器中结束进程来关闭它。在 Linux Mint 上它工作正常。我正在使用线程库中的线程。它也不适用于 QThread。如果我注释掉 thread.join() 行,它会毫无问题地关闭,但该线程运行的代码不会完成。

线程在Window类的__init__()函数中初始化。

self.trackingThread = Thread(target = self.track)

负责跟踪时间的函数:

    def track(self):
startTime = time()
lastWindowChangeTime = startTime
while self.running:
# check if active window has changed
if self.active_window_name != get_active_window_name():
if self.active_window_name in self.applications_time:
self.applications_time[self.active_window_name] += int(time() - lastWindowChangeTime) // 60 # time in minutes)
else:
self.applications_time[self.active_window_name] = int(time() - lastWindowChangeTime) // 60 # time in minutes

lastWindowChangeTime = time()
self.active_window_name = get_active_window_name()


totalTime = int(time() - startTime) // 60 # time in minutes
if date.today() in self.daily_time:
self.daily_time[date.today()] += totalTime
else:
self.daily_time[date.today()] = totalTime

加入线程:

   def saveAndQuit(self):
self.running = False
self.trackingThread.join() # the line that's causing application freeze
self.save()
QApplication.instance().quit()

编辑:例子: https://pastebin.com/vt3BfKJL

相关代码:

def get_active_window_name():
active_window_name = ''

if system() == 'Linux':
active_window_name = check_output(['xdotool', 'getactivewindow', 'getwindowname']).decode('utf-8')
elif system() == 'Windows':
window = GetForegroundWindow()
active_window_name = GetWindowText(window)

return active_window_name

编辑2:删除这两行后应用程序关闭没有任何问题。除了 win32gui 之外,在 Windows 上是否还有其他获取事件窗口名称的方法?:

window = GetForegroundWindow()
active_window_name = GetWindowText(window)

最佳答案

出现此问题是因为 GetWindowText() 处于阻塞状态,因此您的线程永远无法加入。要了解原因,我们必须深入研究 win32 documentation

If the target window is owned by the current process, GetWindowText causes a WM_GETTEXT message to be sent to the specified window or control. If the target window is owned by another process and has a caption, GetWindowText retrieves the window caption text. If the window does not have a caption, the return value is a null string. This behavior is by design. It allows applications to call GetWindowText without becoming unresponsive if the process that owns the target window is not responding. However, if the target window is not responding and it belongs to the calling application, GetWindowText will cause the calling application to become unresponsive.

您正试图从 Qt 事件循环调用的函数 (saveAndQuit) 中加入线程。因此,在该函数返回之前,Qt 事件循环不会处理任何消息。这意味着在另一个线程中对 GetWindowText 的调用已向 Qt 事件循环发送了一条消息,该消息在 saveAndQuit 完成之前不会被处理。但是,saveAndQuit 正在等待线程完成,因此出现了死锁!

有几种解决死锁的方法,最容易实现的可能是从 Qt 事件循环递归调用 join,并设置超时。它有点“hacky”,但其他替代方案意味着诸如更改线程行为方式或使用 QThreads 之类的事情。

因此,我将按如下方式修改您的saveAndQuit:

def saveAndQuit(self):
self.running = False
self.trackingThread.join(timeout=0.05)
# if thread is still alive, return control to the Qt event loop
# and rerun this function in 50 milliseconds
if self.trackingThread.is_alive():
QTimer.singleShot(50, self.saveAndQuit)
return
# if the thread has ended, then save and quit!
else:
self.save()
QApplication.instance().quit()

关于python 应用程序在 thread.join() 上卡住,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48528247/

29 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com