slots are being called multiple times
-
I have the following code that gets called whenever a user opens a file, so this code can be called multiple times.
{ QWidget *tab = getTabWidgetByName(name); mIO = new MIO(this); mIO->moveToThread(&mIOThread); connect(&mIOThread, &QThread::finished, mIO, &QObject::deleteLater); connect(this, &MainWindow::startMIO, this, [this] () -> void { mIO->operator()(); }, Qt::UniqueConnection); connect(mIO, &MIO::notifyMIOFinished, this, &MainWindow::mIOFinished, Qt::UniqueConnection); mIOThread.start(); emit startMIO(); }It works fine until the second time it's called. When run, it appears to be emitting startMIO() twice. The functor mIO->operator()() is certainly called twice somehow and I'm wondering if I'm starting the thread correctly as I call start() on mIOThread. It shouldn't do anything as the constructor is basically empty, and then when emit startMIO() is called, it starts the functor which is where all the work is at.
I saw several other threads about this, and have added Qt::UniqueConnection, but that doesn't seem to help.
Here's a bit about the MIO object.
class MIO : public QObject { Q_OBJECT private: MIO(MainWindow *win); ~MIO(); void operator()(); // ... } MIO::MIO(MainWindow *win) : mainWin(win) { } void MIO::operator()() { // lots of stuff }Thoughts?
-
It's a problem with your usage of
Qt::UniqueConnectionin a connect statement with a lambda. Each time a different instance of that lambda object is created so the connection to it is made. The wayQt::UniqueConnectionworks is it compares the addresses of the objects and function pointers of the signal and slot and doesn't make a connection if all of thouse match something existing.In short
Qt::UniqueConnectiondoesn't work with lambdas so replace the lambda with a normal member function.
Another solution is to store the result of the connect statement ( aQMetaObject::Connectionobject) and use it to calldisconnectafter the connection is triggered.Also note that your usage of connect is kinda dangerous, You passed
thisas the first and third parameter so the connection lives as long asthislives. Inside the lambda you are using thatmIOobject though, that can be destroyed anytime so your app may crash ifmIOis deleted and the signal is emited after that. It's better to tie the connection to the object you're using in the lambda, so instead of usingthisas the third parameter you can usemIO. This way if eitherthisormIOis deleted the connection will be severed automatically.Another consideration is that slots are executed in the thread of the target object, so if you pass
thisas the third parameter the lambda will be called on the thread thatthislives in, notmIOand that's probably not what you want. PassingmIOas the third argument would solve that too. -
I have the following code that gets called whenever a user opens a file, so this code can be called multiple times.
{ QWidget *tab = getTabWidgetByName(name); mIO = new MIO(this); mIO->moveToThread(&mIOThread); connect(&mIOThread, &QThread::finished, mIO, &QObject::deleteLater); connect(this, &MainWindow::startMIO, this, [this] () -> void { mIO->operator()(); }, Qt::UniqueConnection); connect(mIO, &MIO::notifyMIOFinished, this, &MainWindow::mIOFinished, Qt::UniqueConnection); mIOThread.start(); emit startMIO(); }It works fine until the second time it's called. When run, it appears to be emitting startMIO() twice. The functor mIO->operator()() is certainly called twice somehow and I'm wondering if I'm starting the thread correctly as I call start() on mIOThread. It shouldn't do anything as the constructor is basically empty, and then when emit startMIO() is called, it starts the functor which is where all the work is at.
I saw several other threads about this, and have added Qt::UniqueConnection, but that doesn't seem to help.
Here's a bit about the MIO object.
class MIO : public QObject { Q_OBJECT private: MIO(MainWindow *win); ~MIO(); void operator()(); // ... } MIO::MIO(MainWindow *win) : mainWin(win) { } void MIO::operator()() { // lots of stuff }Thoughts?
edit What @Chris-Kawa said.
Given the limited context, use of a dedicated QThread seems overly complicated. QtConcurrent::run may be a better solution.