# Copyright (c) 2015 Shotgun Software Inc.
#
# CONFIDENTIAL AND PROPRIETARY
#
# This work is provided "AS IS" and subject to the Shotgun Pipeline Toolkit
# Source Code License included in this distribution package. See LICENSE.
# By accessing, using, copying or modifying this work you indicate your
# agreement to the Shotgun Pipeline Toolkit Source Code License. All rights
# not expressly granted therein are reserved by Shotgun Software Inc.
"""
Worker thread for the background manager.
"""
import traceback
from sgtk.platform.qt import QtCore
from threading import Lock, Condition
[docs]class WorkerThread(QtCore.QThread):
"""
Asynchronous worker thread that can run tasks in a separate thread. This implementation
implements a custom run method that loops over tasks until asked to quit.
"""
def __init__(self, results_dispatcher, parent=None):
"""
Construction
:param results_dispatcher: Results dispatcher from the background task manager.
:param parent: The parent QObject for this thread
"""
QtCore.QThread.__init__(self, parent)
self._task = None
self._process_tasks = True
self._mutex = Lock()
self._wait_condition = Condition(self._mutex)
self._results_dispatcher = results_dispatcher
[docs] def run_task(self, task):
"""
Run the specified task
:param task: The task to run
"""
with self._mutex:
self._task = task
self._wait_condition.notifyAll()
[docs] def shut_down(self):
"""
Shut down the thread and wait for it to exit before returning
"""
self._results_dispatcher = None
with self._mutex:
self._process_tasks = False
self._wait_condition.notifyAll()
self.wait()
[docs] def run(self):
"""
The main thread run function. Loops over tasks until asked to exit.
"""
try:
while True and self._results_dispatcher is not None:
# get the next task to process:
task_to_process = None
with self._mutex:
while self._process_tasks and not task_to_process:
task_to_process = self._task
self._task = None
if not task_to_process:
# wait until we have something to do...
self._wait_condition.wait()
if not self._process_tasks:
# stop processing
break
# run the task:
try:
result = task_to_process.run()
with self._mutex:
if not self._process_tasks:
break
# emit the result (non-blocking):
self._results_dispatcher.emit_completed(self, task_to_process, result)
except Exception, e:
# something went wrong so emit failed signal:
with self._mutex:
if not self._process_tasks:
break
tb = traceback.format_exc()
# emit failed signal (non-blocking):
self._results_dispatcher.emit_failure(self, task_to_process, str(e), tb)
except RuntimeError:
# We have a situation in Qt5 where it appears that the thread
# is being garbage collected more quickly than in Qt4. In this
# case, we can be pretty sure that we're being shut down, and
# can simply return out of the run loop.
return