【问题标题】:Crash after several seconds of execution with multithreading [duplicate]使用多线程执行几秒钟后崩溃[重复]
【发布时间】:2020-06-30 21:20:38
【问题描述】:

基于herehere 的代码,我在PyQt5 中迈出了多线程的第一步。启动程序后,出现图形用户界面,但几秒钟后它崩溃并出现以下错误

Process finished with exit code -1073740791 (0xC0000409)

在谷歌搜索错误消息后,我比较确定多线程有问题。不幸的是,我不知道错误是什么以及如何修复。

代码

import sys
from datetime import datetime

import wmi

from PyQt5. QtCore import QObject, QRunnable, QThreadPool, pyqtSignal, pyqtSlot
from PyQt5.QtWidgets import QApplication, QMainWindow, QTableWidget, QTableWidgetItem, QHeaderView


class KeyboardDetectorSignals(QObject):
    keyboard_changed = pyqtSignal(str)


class KeyboardDetector(QRunnable):

    def __init__(self):
        super().__init__()

        self.signals = KeyboardDetectorSignals()

    def run(self):

        device_connected_wql = "SELECT * FROM __InstanceCreationEvent WITHIN 2 WHERE TargetInstance ISA \'Win32_Keyboard\'"
        device_disconnected_wql = "SELECT * FROM __InstanceDeletionEvent WITHIN 2 WHERE TargetInstance ISA \'Win32_Keyboard\'"

        c = wmi.WMI()
        connected_watcher = c.watch_for(raw_wql=device_connected_wql)
        disconnected_watcher = c.watch_for(raw_wql=device_disconnected_wql)

        while True:
            try:
                connected = connected_watcher(timeout_ms=10)
            except wmi.x_wmi_timed_out:
                pass
            else:
                if connected:
                    self.signals.keyboard_changed.emit("Keyboard connected.")

            try:
                disconnected = disconnected_watcher(timeout_ms=10)
            except wmi.x_wmi_timed_out:
                pass
            else:
                if disconnected:
                    self.signals.keyboard_changed.emit("Keyboard disconnected.")


class MainWindow(QMainWindow):

    def __init__(self):
        super().__init__()

        self.setGeometry(100, 100, 500, 500)
        self.setWindowTitle("Keyboard Logger")

        self.log_table = QTableWidget()
        self.log_table.setColumnCount(2)
        self.log_table.setShowGrid(True)
        self.log_table.setHorizontalHeaderLabels(["Time", "Event"])
        self.log_table.horizontalHeader().setStretchLastSection(True)
        self.log_table.horizontalHeader().setSectionResizeMode(QHeaderView.ResizeToContents)
        self.setCentralWidget(self.log_table)
        self.show()

        self.threadpool = QThreadPool()
        keyboard_detector = KeyboardDetector()
        keyboard_detector.signals.keyboard_changed.connect(self.add_row)
        self.threadpool.start(keyboard_detector)

    def add_row(self, event: str):
        now = datetime.now()
        datetime_string = now.strftime("%Y-%m-%d %H:%M:%S")

        row_count = self.log_table.rowCount()
        self.log_table.insertRow(row_count)
        self.log_table.setItem(row_count, 0, QTableWidgetItem(datetime_string))
        self.log_table.setItem(row_count, 1, QTableWidgetItem(event))


def main():
    app = QApplication(sys.argv)
    window = MainWindow()
    sys.exit(app.exec_())


if __name__ == '__main__':
    main()

更新 1: 删除了 @pyqtSlot()

从 CMD 运行脚本时出现以下错误:

Traceback (most recent call last):
  File "c:\users\ata\pycharmprojects\test\src\wmi\wmi.py", line 1340, in connect
    obj = GetObject(moniker)
  File "C:\Users\ata\AppData\Local\Programs\Python\Python37\lib\site-packages\win32com\client\__init__.py", line 72, in GetObject
    return Moniker(Pathname, clsctx)
  File "C:\Users\ata\AppData\Local\Programs\Python\Python37\lib\site-packages\win32com\client\__init__.py", line 87, in Moniker
    moniker, i, bindCtx = pythoncom.MkParseDisplayName(Pathname)
pywintypes.com_error: (-2147221020, 'Ung³ltige Syntax', None, None)

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "c:\users\ata\pycharmprojects\test\src\wmi\wmi.py", line 1354, in connect
    handle_com_error()
  File "c:\users\ata\pycharmprojects\test\src\wmi\wmi.py", line 258, in handle_com_error
    raise klass(com_error=err)
wmi.x_wmi_uninitialised_thread: <x_wmi: Unexpected COM Error (-2147221020, 'Ung³ltige Syntax', None, None)>

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "main.py", line 26, in run
    c = wmi.WMI()
  File "c:\users\ata\pycharmprojects\test\src\wmi\wmi.py", line 1357, in connect
    raise x_wmi_uninitialised_thread("WMI returned a syntax error: you're probably running inside a thread without first calling pythoncom.CoInitialize[Ex]")
wmi.x_wmi_uninitialised_thread: <x_wmi: WMI returned a syntax error: you're probably running inside a thread without first calling pythoncom.CoInitialize[Ex] (no underlying exception)>
PS C:\Users\ata\PycharmProjects\Snippets\KeyboardLogger>

【问题讨论】:

  • 您能否从 CMD 运行脚本以获得更具描述性的错误消息?同时删除pyqtSlot
  • @eyllanesc 请参阅更新 1。
  • 添加import pythoncom并在device_connected_wql = "SELECT ...之前添加pythoncom.CoInitialize()
  • @eyllanesc 太棒了!使用 pythoncom 已经解决了这个问题。 pythoncom这个模块我从来没听说过,更别说用过了。

标签: python pyqt pyqt5 python-multithreading


【解决方案1】:

PyQt 是线程安全的,与Qt 是线程安全的程度相同。 Qt docs 会告诉您他们的 API 的哪些部分可以保证如此,以及在什么情况下。

Cross-thread signalsthread-safe.

编写此代码的线程安全方式是使用mutex

【讨论】:

  • 谢谢。我也从未使用过mutex
猜你喜欢
  • 1970-01-01
  • 2013-12-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-04-14
  • 2020-10-26
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多