From d94c934e479b3a5c75deb09244b810387e52e9b0 Mon Sep 17 00:00:00 2001 From: SomberNight Date: Mon, 26 Sep 2022 20:10:44 +0000 Subject: [PATCH] qt main_window: _coroutines_scheduled needs locking window.run_coroutine_from_thread starts a coroutine on the asyncio loop, which, when finishing, pops from the dict. The for loop in clean_up is running on the Qt thread. fixes https://github.com/spesmilo/electrum/issues/7983 --- electrum/gui/qt/main_window.py | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/electrum/gui/qt/main_window.py b/electrum/gui/qt/main_window.py index cfd08d2ec..ac4a44fe1 100644 --- a/electrum/gui/qt/main_window.py +++ b/electrum/gui/qt/main_window.py @@ -189,6 +189,7 @@ class ElectrumWindow(QMainWindow, MessageBoxMixin, Logger, QtEventListener): Logger.__init__(self) self._coroutines_scheduled = {} # type: Dict[concurrent.futures.Future, str] + self._coroutines_scheduled_lock = threading.Lock() self.thread = TaskThread(self, self.on_error) self.tx_notification_queue = queue.Queue() @@ -310,11 +311,13 @@ class ElectrumWindow(QMainWindow, MessageBoxMixin, Logger, QtEventListener): if on_result: on_result(res) finally: - self._coroutines_scheduled.pop(fut) + with self._coroutines_scheduled_lock: + self._coroutines_scheduled.pop(fut) self.need_update.set() fut = asyncio.run_coroutine_threadsafe(wrapper(), self.network.asyncio_loop) - self._coroutines_scheduled[fut] = name + with self._coroutines_scheduled_lock: + self._coroutines_scheduled[fut] = name self.need_update.set() def on_fx_history(self): @@ -999,7 +1002,8 @@ class ElectrumWindow(QMainWindow, MessageBoxMixin, Logger, QtEventListener): if num_tasks == 0: name = '' elif num_tasks == 1: - name = list(self._coroutines_scheduled.values())[0] + '...' + with self._coroutines_scheduled_lock: + name = list(self._coroutines_scheduled.values())[0] + '...' else: name = "%d"%num_tasks + _('tasks') + '...' self.tasks_label.setText(name) @@ -2494,7 +2498,9 @@ class ElectrumWindow(QMainWindow, MessageBoxMixin, Logger, QtEventListener): if self.thread: self.thread.stop() self.thread = None - for fut in self._coroutines_scheduled.keys(): + with self._coroutines_scheduled_lock: + coro_keys = list(self._coroutines_scheduled.keys()) + for fut in coro_keys: fut.cancel() self.unregister_callbacks() self.config.set_key("is_maximized", self.isMaximized())