killTimer: Timers cannot be stopped from another thread
-
I want to use QTimer in another thread, this is full repo.
While exit from proj I get error
QObject::killTimer: Timers cannot be stopped from another thread QObject::~QObject: Timers cannot be stopped from another thread
Why? A piece of code from repo.
Main threadconnect(this, &MainClass::GetTimeAsk, worker.get(), &Worker::GetTime, Qt::QueuedConnection); QTimer *askTim(new QTimer(this)); connect(askTim, &QTimer::timeout, this, [&]{ qDebug().noquote().nospace() << "thread;askTim;" << QThread::currentThreadId(); emit GetTimeAsk(); }); askTim->start(400);
Worker thread
void Worker::GetTime(){ static uint i; qDebug().noquote().nospace() << "thread;GetTime;" << QThread::currentThreadId() << ";" << i++; tim->start(); }
- Looks like problem reason is
emit GetTimeAsk()
but this signal is connected to slot usingQt::QueuedConnection
connection type:
"Queued Connection The slot is invoked when control returns to the event loop of the receiver's thread. The slot is executed in the receiver's thread"
connect(this, &MainClass::GetTimeAsk, worker.get(), &Worker::GetTime, Qt::QueuedConnection);
- And threads is really different:
emit GetTimeAsk()
located in thread 0x7b6260960000 and slotGetTime()
is started from 0x7b625ca006c0 thread... Sounds like problem should not be but in log we have
QObject::killTimer: Timers cannot be stopped from another thread QObject::~QObject: Timers cannot be stopped from another thread
- Insted of
Qt::QueuedConnection
I have triedQt::AutoConnection
, but problem still the same. - Another idea was that
tim= new QTimer(this)
is started in incorrect thread but I don't think so because in log I see firstthread->start()
and thenWorker::run
. - Anothere idead is to use QScopedPointer:
QScopedPointer<QTimer> tim
instead ofQTimer *tim
, but problem is the same.
- Looks like problem reason is
-
@jsulm thanks, now works, I tested by this code, log is without problem:
$ ./QThread_QTimer Worker::Worker MainWindow::MainWindow thread->start() parents QObject(0x0) MainClass(0x7fff7673c740) Worker::run ^CWelcome to Signal handled: 2 requestInterruption emit finished() ~Worker() threadIsFinished ~MainWindow()
Should I open bug report about QScopedPointer in multi-thread proj?
P.S. With std::unique_ptr the same problem like with QScopedPointer...
@DungeonLords said in killTimer: Timers cannot be stopped from another thread:
Should I open bug report about QScopedPointer in multi-thread proj?
There is no bug.
It's not the job of the QScopedPointer to know in which thread the object lives which it is managing.
The correct way in Qt to delete objects living in other threads is to use deleteLater(). -
I want to use QTimer in another thread, this is full repo.
While exit from proj I get error
QObject::killTimer: Timers cannot be stopped from another thread QObject::~QObject: Timers cannot be stopped from another thread
Why? A piece of code from repo.
Main threadconnect(this, &MainClass::GetTimeAsk, worker.get(), &Worker::GetTime, Qt::QueuedConnection); QTimer *askTim(new QTimer(this)); connect(askTim, &QTimer::timeout, this, [&]{ qDebug().noquote().nospace() << "thread;askTim;" << QThread::currentThreadId(); emit GetTimeAsk(); }); askTim->start(400);
Worker thread
void Worker::GetTime(){ static uint i; qDebug().noquote().nospace() << "thread;GetTime;" << QThread::currentThreadId() << ";" << i++; tim->start(); }
- Looks like problem reason is
emit GetTimeAsk()
but this signal is connected to slot usingQt::QueuedConnection
connection type:
"Queued Connection The slot is invoked when control returns to the event loop of the receiver's thread. The slot is executed in the receiver's thread"
connect(this, &MainClass::GetTimeAsk, worker.get(), &Worker::GetTime, Qt::QueuedConnection);
- And threads is really different:
emit GetTimeAsk()
located in thread 0x7b6260960000 and slotGetTime()
is started from 0x7b625ca006c0 thread... Sounds like problem should not be but in log we have
QObject::killTimer: Timers cannot be stopped from another thread QObject::~QObject: Timers cannot be stopped from another thread
- Insted of
Qt::QueuedConnection
I have triedQt::AutoConnection
, but problem still the same. - Another idea was that
tim= new QTimer(this)
is started in incorrect thread but I don't think so because in log I see firstthread->start()
and thenWorker::run
. - Anothere idead is to use QScopedPointer:
QScopedPointer<QTimer> tim
instead ofQTimer *tim
, but problem is the same.
@DungeonLords said in killTimer: Timers cannot be stopped from another thread:
tim->start();
Where is tim living (in which thread)? You just have to make sure the timer lives in the thread where it is used. Usually you achieve it by creating it in the thread.
- Looks like problem reason is
-
@DungeonLords said in killTimer: Timers cannot be stopped from another thread:
tim->start();
Where is tim living (in which thread)? You just have to make sure the timer lives in the thread where it is used. Usually you achieve it by creating it in the thread.
@jsulm askTim located in main thread but it's slot GetTime() is located in worker thread...
-
@jsulm askTim located in main thread but it's slot GetTime() is located in worker thread...
@DungeonLords I asked about tim, not askTim.
Again: where and when is tim created? -
@DungeonLords I asked about tim, not askTim.
Again: where and when is tim created? -
@DungeonLords said in killTimer: Timers cannot be stopped from another thread:
tim is created in Worker thread
Are you sure? Can you please show where exactly you're creating it?
-
@DungeonLords said in killTimer: Timers cannot be stopped from another thread:
tim is created in Worker thread
Are you sure? Can you please show where exactly you're creating it?
void Worker::run() { qDebug() << "Worker::run"; tim= new QTimer(this); //<<here connect(tim, &QTimer::timeout, this, &Worker::timer_clb, static_cast<Qt::ConnectionType>(Qt::AutoConnection | Qt::UniqueConnection)); tim->setInterval(400); while(1)
Worker::run() is not a constructor and doesn't call from Worker's constructor. Worker's run() method starts by thread's signal started():
connect(thread.get(), &QThread::started, worker.get(), &Worker::run); thread->start();
-
void Worker::run() { qDebug() << "Worker::run"; tim= new QTimer(this); //<<here connect(tim, &QTimer::timeout, this, &Worker::timer_clb, static_cast<Qt::ConnectionType>(Qt::AutoConnection | Qt::UniqueConnection)); tim->setInterval(400); while(1)
Worker::run() is not a constructor and doesn't call from Worker's constructor. Worker's run() method starts by thread's signal started():
connect(thread.get(), &QThread::started, worker.get(), &Worker::run); thread->start();
@DungeonLords said in killTimer: Timers cannot be stopped from another thread:
QTimer(this)
So you create it in the main thread as the QThread object lives in the main thread.
-
void Worker::run() { qDebug() << "Worker::run"; tim= new QTimer(this); //<<here connect(tim, &QTimer::timeout, this, &Worker::timer_clb, static_cast<Qt::ConnectionType>(Qt::AutoConnection | Qt::UniqueConnection)); tim->setInterval(400); while(1)
Worker::run() is not a constructor and doesn't call from Worker's constructor. Worker's run() method starts by thread's signal started():
connect(thread.get(), &QThread::started, worker.get(), &Worker::run); thread->start();
@DungeonLords The problem is probably that you use a scoped pointer for the worker, so it is deleted in main thread. Use raw pointer and connect thread finished signal to deletLater() slot of the worker.
-
@DungeonLords The problem is probably that you use a scoped pointer for the worker, so it is deleted in main thread. Use raw pointer and connect thread finished signal to deletLater() slot of the worker.
@jsulm thanks, now works, I tested by this code, log is without problem:
$ ./QThread_QTimer Worker::Worker MainWindow::MainWindow thread->start() parents QObject(0x0) MainClass(0x7fff7673c740) Worker::run ^CWelcome to Signal handled: 2 requestInterruption emit finished() ~Worker() threadIsFinished ~MainWindow()
Should I open bug report about QScopedPointer in multi-thread proj?
P.S. With std::unique_ptr the same problem like with QScopedPointer...
-
@jsulm thanks, now works, I tested by this code, log is without problem:
$ ./QThread_QTimer Worker::Worker MainWindow::MainWindow thread->start() parents QObject(0x0) MainClass(0x7fff7673c740) Worker::run ^CWelcome to Signal handled: 2 requestInterruption emit finished() ~Worker() threadIsFinished ~MainWindow()
Should I open bug report about QScopedPointer in multi-thread proj?
P.S. With std::unique_ptr the same problem like with QScopedPointer...
@DungeonLords said in killTimer: Timers cannot be stopped from another thread:
Should I open bug report about QScopedPointer in multi-thread proj?
There is no bug.
It's not the job of the QScopedPointer to know in which thread the object lives which it is managing.
The correct way in Qt to delete objects living in other threads is to use deleteLater(). -
-
void Worker::run() { qDebug() << "Worker::run"; tim= new QTimer(this); //<<here connect(tim, &QTimer::timeout, this, &Worker::timer_clb, static_cast<Qt::ConnectionType>(Qt::AutoConnection | Qt::UniqueConnection)); tim->setInterval(400); while(1)
Worker::run() is not a constructor and doesn't call from Worker's constructor. Worker's run() method starts by thread's signal started():
connect(thread.get(), &QThread::started, worker.get(), &Worker::run); thread->start();
@DungeonLords said in killTimer: Timers cannot be stopped from another thread:
void Worker::run()
processEvents()
in an infinite loop is not the best solution here. This will produce code that will use a single core a 100%. People will start asking questions why your app is using 100% of one core while it is doing nothing (I'm speaking from experience). The proper solution is to callexec()
instead. However, this is also already the default implementation ofQThread::run()
. So, you can just leverage that and throw away your entire while-loop. Maybe then don't call your methodrun()
but justcreateTimer()
. Then it makes a lot more sense to callconnect(thread.get(), &QThread::started, worker.get(), &Worker::createTimer());
, i.e.createTimer
whenthread
isstarted
. (Instead of usingrequestInterruption
you would then just callquit
.)The use of
exit_LABEL
shows some lack of understanding of asynchronous programming, which is the natural way in Qt. Send signals connected to slots instead to perform such operations. Just out of curiosity: Was AI heavily involved in creating this code? Or are you just coming from embedded systems programming?emit GetTimeAsk();
does not make sense.emit
is usually used for signals only (it compiles because it is replaced by nothing by the preprocessor). Effectively you are just executing a normal member function. This also means that this is just executed in the main thread. (Which in turn means that incrementingi
is not thread safe.)