Complete implementation of blocking mechanism waiting for signal. See #196.

This commit is contained in:
Juan Pablo Caram 2016-03-24 16:06:44 -04:00
parent b0575a1c34
commit a520729444
2 changed files with 36 additions and 13 deletions

View File

@ -11,6 +11,7 @@ import Tkinter
from PyQt4 import QtCore
import time # Just used for debugging. Double check before removing.
from xml.dom.minidom import parseString as parse_xml_string
from contextlib import contextmanager
########################################
## Imports part of FlatCAM ##
@ -106,6 +107,10 @@ class App(QtCore.QObject):
message = QtCore.pyqtSignal(str, str, str)
# Emitted when an unhandled exception happens
# in the worker task.
thread_exception = QtCore.pyqtSignal(object)
def __init__(self, user_defaults=True, post_gui=None):
"""
Starts the application.
@ -2138,13 +2143,22 @@ class App(QtCore.QObject):
return a, kwa
from contextlib import contextmanager
@contextmanager
def wait_signal(signal, timeout=10000):
"""Block loop until signal emitted, or timeout (ms) elapses."""
"""
Block loop until signal emitted, timeout (ms) elapses
or unhandled exception happens in a thread.
:param signal: Signal to wait for.
"""
loop = QtCore.QEventLoop()
# Normal termination
signal.connect(loop.quit)
# Termination by exception in thread
self.thread_exception.connect(loop.quit)
status = {'timed_out': False}
def report_quit():
@ -2153,17 +2167,23 @@ class App(QtCore.QObject):
yield
# Temporarily change how exceptions are managed.
oeh = sys.excepthook
ex = []
def exceptHook(type_, value, traceback):
ex.append(value)
oeh(type_, value, traceback)
sys.excepthook = exceptHook
def except_hook(type_, value, traceback_):
ex.append(value)
oeh(type_, value, traceback_)
sys.excepthook = except_hook
# Terminate on timeout
if timeout is not None:
QtCore.QTimer.singleShot(timeout, report_quit)
#### Block ####
loop.exec_()
# Restore exception management
sys.excepthook = oeh
if ex:
self.raiseTclError(str(ex[0]))

View File

@ -14,24 +14,27 @@ class Worker(QtCore.QObject):
self.name = name
def run(self):
# FlatCAMApp.App.log.debug("Worker Started!")
self.app.log.debug("Worker Started!")
# Tasks are queued in the event listener.
self.app.worker_task.connect(self.do_worker_task)
def do_worker_task(self, task):
# FlatCAMApp.App.log.debug("Running task: %s" % str(task))
self.app.log.debug("Running task: %s" % str(task))
# 'worker_name' property of task allows to target
# specific worker.
if 'worker_name' in task and task['worker_name'] == self.name:
task['fcn'](*task['params'])
return
if ('worker_name' in task and task['worker_name'] == self.name) or \
('worker_name' not in task and self.name is None):
try:
task['fcn'](*task['params'])
except Exception as e:
self.app.thread_exception.emit(e)
raise e
if 'worker_name' not in task and self.name is None:
task['fcn'](*task['params'])
return
# FlatCAMApp.App.log.debug("Task ignored.")