I have a worker class
class Worker(QObject):
finished = Signal()
def __init__(self, n):
super().__init__()
self.a_flag = False
# self.mutex = QMutex()
# @Slot()
def stop(self):
self.a_flag = True
@Slot()
def do_work(self):
while True:
if self.a_flag:
break
# do some wo
self.finished.emit()
And somewhere in the controller (from main thread) I am moving it to a new thread
self.worker = Worker(num)
self.worker_thread = QThread()
self.worker.moveToThread(self.worker_thread)
After self.worker.moveToThread(self.worker_thread)
the thread affinity of worker
is changed and I guess I can't access the members of worker
in controller (I am not sure about it but I can argue why). Is there any reference that say's anything about it?
Is it safe to do self.a_flag = True
somewhere in controller (main thread) or call stop()
?
Is there any workaround to notify do_work
to get out of the loop?
Can I call a
QObject
method from main thread aftermoveToThread()
method is called?
Yes.
What thread affinity means queued events or posted events received by QObject
will now be handled by new thread (the one where it moved to). moveToThread()
will only change the thread affinity of worker
(it doesn't really move the object!) and therefore main thread can access worker
.
Now this raise another question: is it safe to modify a_flag
in main thread while it is being used by secondary thread?
Yes.
Reason we can set worker.a_flag
in main thread
a_flag
is a boolean and setting it is an atomic operation in python. This makes it thread safe and can be set in main threada_flag
is always set by one thread (main thread) and read by another.Also note that in case of doubt, use mutex!
def __init__(self, n):
super().__init__()
self.a_flag = False
self.mutex = QMutex()
def stop(self):
self.mutex.lock()
self.a_flag = True
self.mutex.unlock()
Acquiring lock here not put much overhead, IMO.
Note that if another thread also set boolean variable after reading it then this operation is not thread safe. Mutex lock is needed in this case. (more on this here]