Solved Can't seem to start two QThreads one after the other from the same function.
-
self._project.runner().eventOccurred.connect(self._sessionThread.stateMachineEventOccurs) self._sessionThread.setRunning(True) self._project.runStateMachine() self._sessionThread.start() #self._project.runner().stateMachineStarted.connect(lambda: self._sessionThread.setRunning(True))
If I comment out
runStateMachine()
which internally / directly / similarly starts another thread constructed as the same type of subclass ofQThread
; thenself._sessionThread.start()
will go through and work. But when they're both present, just the state machine starts, and I can't get the session thread to start ('run' I mean... nothing printed in run() method nor can I break there). -
This post is deleted! -
@enjoysmath
QThread::start()
does nothing if the thread is already running.If I comment out runStateMachine() which internally / directly / similarly starts another thread constructed as the same type of subclass of QThread;
You sure they're not running on the same thread? Just a thought.
-
Hi,
@enjoysmath said in Can't seem to start two QThreads one after the other from the same function.:
self._sessionThread.setRunning(True)
self._project.runStateMachine()
self._sessionThread.start()Something strange here, why both setRunning and start ?
-
@SGaist the reason I do that is because I can't seem to override
start()
in my QThread subclasses, which would normally do the job ofsetRunning(True)
.Essentially I want two independent threads
-
Here's what I'm working on. Of course I'd need a separate thread to run the state machine and a thread to run the recorder. I don't want to mix the two, and they cannot block the GUI!
Thanks for any links / guidance.
What's that article about how to choose the right Qt Threading solution?
-
Because start is not a virtual function.
@enjoysmath said in Can't seem to start two QThreads one after the other from the same function.:
_project.runStateMachine
How is that method implemented ?
And why a thread for your state machine ? QStateMachine already spins it's own event loop so you don't really need a separate thread for it.
-
I'm not using QStateMachine - because it had no particular features I was going to use. This is a DSL for leds (the text), so no keyboard events.
My state machine runner works, though is kind of iffy, but definitely depends on being run on a QRunnable or QThread.
@SGaist thanks for your quick response!
š
šµ -
I've changed it to QThreadPool with two QRunnables started() on it. But I think it's still doing the same thing - only one thread at a time.
```
def killStateMachine(self):
self._window.scene.setInSimulation(False)
self._runner.abort()def runStateMachine(self): thread = self.createRunnerThread() thread.setRunning(True) thread.start() def createRunnerThread(self): start_state = self.getStartState() if start_state: self._window.scene.setInSimulation(True) self._runner.setStartState(start_state) return self._runner.createThread() else: self._window.showStatusMessage( "No start state found. Make sure there's a state with no arrows going into it.", 7000, 'color:maroon;') return None
My impls kindof confusing. Should I work on a minimal example?
-
That would be nice yes.
It seems to be really convoluted. Rather than having a thread handling your object (like the worker object concept) you seem to create the thread from the object itself and then ??
Also, you seem to want to modify your GUI from these threads which is wrong.
-
Here's what I think is going on now. I saw that the internals of my RunnerThread class have been replaced with a QTimer. Probably from when I was having some unrelated problems with QThreads.
So my first thought was to convert both thread classes to QTimers internally (effectively not using the thread). But as I was coding this idea, I thought wait, maybe the threads aren't working because:
``` def start(self): self._loopTimer = QTimer() sleep = self._runner.tickSleep() self._loopTimer.setInterval(sleep) self._loopTimer.timeout.connect(self.run) self._loopTimer.setSingleShot(False) self._loopTimer.start() self._state = self._runner.startState() self.setRunning(True) self.exec() # Start Qt event loop def terminate(self): self.setRunning(False) self._loopTimer.stop() self._loopTimer = None
I think maybe that
self.exec()
call is not returning or if it is you can't do what I've done with a QTimer and another QThread implemented the appropriate way.I'll put them both back as real QThreads, and see if that solves this.
-
Okay, here's my findings.
First read the article by Qt about the different threading options. If yours is QThread, then implement them as usual, but create a startRunning / stopRunning methods (in your subclass) which call start / terminate since these methods are not overridable.
Any time I switch on an LED or make a change graphically from the state machine runner thread, I need to implement that as a signal / slot and do the actual LED brightness change in say my MainWindow class, but in the main gui thread is what's important. If you just try to change an LED's brightness you'll notice nothing changes on screen. It's because your graphics scene is running on the main gui thread I think. With QThreads (unlike QRunnable) you can add your pyqtSignals's directly to your QThread subclass.
You can also make a QThread pauseable. Message me if you need to know how.
-
The exec call indeed doesn't return until the loop it started ends.