PDA

View Full Version : QObject::killTimer Warning Messages



mclark
10th September 2008, 22:52
I've noticed the following two warning messages in my debug output window when my app exits. I'm running Qt 4.3.4 under Visual Studio 2005.


QObject::killTimer: timers cannot be stopped from another thread
QObject::killTimers: timers cannot be stopped from another thread

I am using 2 QTimers in my app. One is a private member in a QThread (where I believe the warnings are coming from). The other is a private member of my QMainWindow, but the way I'm using the app, the timer shouldn't be created (it should only be created when running the app from the command-line).

Can anyone give me some insight as to what could be causing these messages?



////////////////////////////////////////////////////////////////////////////////
// In the constructor of the QMainWIndow
m_pPropTimer = NULL;

m_pPropTimer = new QTimer( this );
connect( m_pPropTimer, SIGNAL( timeout() ), this, SLOT( nonGUIReadTimeout() ) );

// In the destructor of the QMainWIndow
if ( (m_pPropTimer != NULL) && m_pPropTimer->isActive() )
m_pPropTimer->stop();
////////////////////////////////////////////////////////////////////////////////

// This class is what I believe is causing the messages
WatchDogThread::WatchDogThread( QObject* parent ) : QThread( parent )
{
m_parent = static_cast<CController*>( parent );
m_pTimer = NULL;
}

WatchDogThread::~WatchDogThread( void )
{
if ( m_pTimer != NULL )
{
if ( m_pTimer->isActive() )
m_pTimer->stop();

delete m_pTimer;
}
}

void WatchDogThread::run( void )
{
m_pTimer = new QTimer();
connect( m_pTimer, SIGNAL( timeout() ), this, SLOT( checkTimestamp() ) );
m_pTimer->start( 5000 );

exec();
}

wysota
10th September 2008, 23:24
The thread object doesn't live in the thread it creates thus the destructor runs in the main thread and not your worker thread. Move the contents of your destructor into the run() method right after exec().

mclark
10th September 2008, 23:55
Thanks for the reply. I placed the timer deletion code in the run() method but after exec() returns, the m_pTimer member value indicates that the QTimer instance has been deleted. The end result, of course, is a crash in QTimer because the value is bad.

What\Who is deleting the QTimer?
Why is the m_pTimer value valid immediately after exec() returns but invalid when isActive() is called?
Would it be better to handle the deletion of m_pTimer in response to the QThread::finished() signal?


m_pTimer BEFORE exec() 0x1d8fc48
m_pTimer AFTER exec() 0x1d8fc48
m_pTimer BEFORE isActive() 0xfeeefeee


void WatchDogThread::run( void )
{
m_pTimer = new QTimer();
connect( m_pTimer, SIGNAL( timeout() ), this, SLOT( checkTimestamp() ) );
m_pTimer->start( 5000 );

qDebug( "m_pTimer BEFORE exec() 0x%x", m_pTimer );
exec();
qDebug( "m_pTimer AFTER exec() 0x%x", m_pTimer );

if ( m_pTimer != NULL )
{
qDebug( "m_pTimer BEFORE isActive() 0x%x", m_pTimer );
if ( m_pTimer->isActive() ) //<-- CRASH
m_pTimer->stop();

delete m_pTimer;
}
}

wysota
11th September 2008, 08:55
What\Who is deleting the QTimer?
Provided that the timer doesn't have a parent it has to be you or the timer is not deleted at all.

Why is the m_pTimer value valid immediately after exec() returns but invalid when isActive() is called?
Maybe you have a local variable somewhere that is named the same and it shadows the other variable?


Would it be better to handle the deletion of m_pTimer in response to the QThread::finished() signal?
No. If you create an object in run(), destroy it there. The timer won't timeout anyway after you return from exec() so there is no point in keeping it. I even suggest you change your run() a bit:


void ...:run(){
QTimer timer;
connect(&timer, SIGNAL(timeout()), this, SLOT(checkTimestamp()));
timer.start(5000);
exec();
// the timer will get deleted when run() returns
}

By the way, I hope you realize the slot will be called in the context of the main thread and not the worker thread. What is the point in doing all that in a worker thread anyway? Does the thread do anything else besides running the timer?

yxmaomao
11th September 2008, 08:56
I think you should do that in :
QThread::finished()

yxmaomao
11th September 2008, 09:35
Hi Mclark,I have tested your code, every thing is right on my PC,
I am using Qt4.3 with Visual Studio 2005
my code:
-----.h file---------------


class CMyThread : public QThread
{
Q_OBJECT
public:
void run();

private:
QTimer* mTimer;
};

----.cpp file----------------


void CMyThread :: run()
{
mTimer = new QTimer();
mTimer->start(1000);
exec();

if ( mTimer )
{
if ( mTimer->isActive() )
{
mTimer->stop();
}
}
}

in main function
-------------------------------
CMyThread mythread;
mythread.start();
......
mythread.exit();

mclark
11th September 2008, 18:47
Provided that the timer doesn't have a parent it has to be you or the timer is not deleted at all.

Even when I remove the 'delete m_pTimer' code the m_pTimer value changes after returning from exec(). It gets the 0xfeeefeee value. There are no other m_pTimer variables declared anywhere in this class.


By the way, I hope you realize the slot will be called in the context of the main thread and not the worker thread. What is the point in doing all that in a worker thread anyway? Does the thread do anything else besides running the timer?

The purpose of this thread is to:

Maintain a list of objects. When the object is created it is put into the list. When the object is fully initialized (due to outside forces) it is removed from the list.
Run the timer. When the timer times out, the list is checked. If it contains any objects that have been waiting to be initialized for too long, they are rescheduled and removed from the list. At this point the timer is restarted.

I admit I am a novice when it comes to threading, but I don't see why the slot is run in the main threads context instead of the worker thread. The 'this' pointer in the connect() call is the worker thread pointer, no?

wysota
11th September 2008, 21:10
The purpose of this thread is to:

Maintain a list of objects. When the object is created it is put into the list. When the object is fully initialized (due to outside forces) it is removed from the list.
Run the timer. When the timer times out, the list is checked. If it contains any objects that have been waiting to be initialized for too long, they are rescheduled and removed from the list. At this point the timer is restarted.

You don't need a separate thread for that.


I admit I am a novice when it comes to threading, but I don't see why the slot is run in the main threads context instead of the worker thread. The 'this' pointer in the connect() call is the worker thread pointer, no?

No, it is a pointer to an object representing the thread. And the object itself lives in the context of the thread that created it (the object, not the thread) therefore it lives in context of the main thread.