Wenn das folgende Programm mit einem einzigen Befehlszeilenumrand auf Windows ausgeführt wird.
Code: Select all
# threading-crash.py
"""Reproduce a crash involving Qt and threading"""
from PyQt5 import QtCore
import sys
from threading import Thread
from typing import Optional
class WorkerManager(QtCore.QObject):
# Signal emitted when thread is finished.
worker_finished = QtCore.pyqtSignal()
def start_worker(self) -> None:
def worker() -> None:
# Printing here is necessary for the crash to happen *reliably*,
# though it still happens without it (just less often).
print("Emitting worker_finished signal")
self.worker_finished.emit()
t = Thread(target=worker)
t.start()
def run_test() -> None:
# When using `mypy`, I cannot assign `None` to `app` at the end unless
# the type is declared to be optional here.
app: Optional[QtCore.QCoreApplication] = QtCore.QCoreApplication(sys.argv)
assert(app) # Pacify mypy.
mgr = WorkerManager()
def finished() -> None:
# Terminate the `exec_` call below.
assert(app) # Pacify mypy.
app.exit(0)
# Make a queued connection since this is a cross-thread signal. (This
# is not necessary to reproduce the crash; auto does the same thing.)
mgr.worker_finished.connect(
finished, QtCore.Qt.QueuedConnection) # type: ignore
# Start the worker thread, which will signal `finished`.
mgr.start_worker()
# Wait for the signal to be received.
app.exec_()
if len(sys.argv) == 1:
# This fixes the crash!
app = None
def main() -> None:
for i in range(10):
print(f"{i}: run_test")
run_test() # Crashes on the second call.
if __name__ == "__main__":
main()
# EOF
Auf meinem System (und mit dem Druck in Worker ) Dieses Programm
stürzt oder hängt 100% der Zeit im zweiten Run_test call.
Code: Select all
$ python threading-crash.py CRASH
0: run_test
Emitting worker_finished signal
1: run_test
Emitting worker_finished signal
Segmentation fault
Exit 139
< /code>
Das genaue Verhalten variiert unvorhersehbar; Ein weiteres Beispiel: < /p>
$ python threading-crash.py CRASH
0: run_test
Emitting worker_finished signal
1: run_test
Emitting worker_finished signal
Exception in thread Thread-2 (worker):
Traceback (most recent call last):
File "D:\opt\Python311\Lib\threading.py", line 1038, in _bootstrap_inner
Exit 127
< /code>
Andere Möglichkeiten umfassen das Aufpacken eines Fehlerdialogfelds ("Die
-Anweisung bei (hex) referenzierter Speicher bei (hex).") Oder einfach hängen
komplett.
beim Ausführen ohne Argumente, wodurch das
-Anleitungen aktiviert wird, wodurch das
-Anleitungen aktiviert wird, wodurch das
app = None< /code> Zeile, es läuft gut (selbst mit einer großen Iterationsanzahl wie
1000): < /p>
$ python threading-crash.py
0: run_test
Emitting worker_finished signal
1: run_test
Emitting worker_finished signal
[...]
9: run_test
Emitting worker_finished signal
Entfernen des Drucks in start_worker Beitritt zum Worker nach app.exec _ () hilft nicht; Es stürzt immer noch ab. Time.sleep (1) dort (mit oder ohne Join) hilft auch nicht. Dies bedeutet, dass der Absturz geschieht, obwohl zum Zeitpunkt
nur ein Thread ausgeführt wird. /> qtcore.qThread anstelle von Threading.thread hat auch keinen Einfluss auf den Absturz. Insbesondere:
Warum stürzt es nicht ab, wenn ich App bis keine zurücksetze? Sollte dies nicht automatisch
(oder etwas Äquivalentes) auftreten, wenn run_test < /code>
zurückgegeben wird? QCOREAPPLICTS ? In dieser Suite soll jeder
-Test von jedem anderen unabhängig sein, sodass diejenigen Tests, die
erfordern, ein eigenes QCoreApplication < /code> -Objekt erstellen. Die
-Dokumentation scheint dies nicht zu verbieten.$ python -V -V
Python 3.11.5 (tags/v3.11.5:cce6ba9, Aug 24 2023, 14:38:34) [MSC v.1936 64 bit (AMD64)]
$ python -m pip list | grep -i qt
PyQt5 5.15.11
PyQt5-Qt5 5.15.2
PyQt5_sip 12.17.0
PyQt5-stubs 5.15.6.0
< /code>
Ich leite dies unter Windows 10 Home aus. Die obigen Beispiele verwenden eine Cygwin
-Schell, aber dasselbe geschieht unter cmd.exe < /code>. Dies alles verwendet
den nativen Windows -Port von Python. < /P>