Trolltech Home | Qt-interest Home | Recent Threads | All Threads | Author | Date
All threads index page 5

Qt-interest Archive, August 2007
stopping + deleting QTimer


Message 1 in thread

Hey,

right now I'm using a singleShot Timer to run a initialization method
once my QThread enters its event loop. Within this init() method I
initialize an QTimer(this) object.

The problem is: The QTimer keeps running after the QThread event loop quits.
I can't stop and I can't delete the QTimer object from outside the
event loop (after the exec() line in run())

Any ideas?

Jens

-- 
 [ signature omitted ] 

Message 2 in thread

On fredag den 24. August 2007, Jens Luedicke wrote:
> Hey,
>
> right now I'm using a singleShot Timer to run a initialization method
> once my QThread enters its event loop. Within this init() method I
> initialize an QTimer(this) object.
>
> The problem is: The QTimer keeps running after the QThread event loop
> quits. I can't stop and I can't delete the QTimer object from outside the
> event loop (after the exec() line in run())

Show us the code.

Bo.

-- 
 [ signature omitted ] 

Message 3 in thread

On 8/24/07, Bo Thorsen <bo@xxxxxxxxxxxxxxxxxxxxx> wrote:

> Show us the code.
>

here it is:

void MyThread::run() {
	qDebug("%s", Q_FUNC_INFO);

	QTimer::singleShot(0, this, SLOT(init()));

	// exec event loop
	exec();

	// do cleanups
	cleanup();
}

void MyThread::init() {
	// ... init a few variables

	// Update Timer:
	updateTimer = new QTimer(this);
	connect(updateTimer, SIGNAL(timeout()), this, SLOT(doUpdate()));
	updateTimer->start(updateTimeout);
}

void MyThread::cleanup() {
	qDebug("%s", Q_FUNC_INFO);

//	routeUpdateTimer->stop(); // <-- problem 1

//	delete routeUpdateTimer;  // <-- problem 2
//	routeUpdateTimer = 0;
}


Jens

-- 
 [ signature omitted ] 

Message 4 in thread

Hello,

I've had a similar problem.

The trick is that you start a new thread in your main thread for 
example. So the new thread is using the eventloop of the thread in which 
you created the new thread. To make sure the new thread uses his own 
eventloop(exec()), you can add in the constructor of 'MyThread' this line:

moveToThread(this);

And now the timer you create with the new thread as a parent will use 
your new thread's eventloop!

This is nowhere mentionned in the docs I think, but it should be.

greetz,
Tom,

--
 [ signature omitted ] 

Message 5 in thread

On 24.08.07 10:27:47, Jens Luedicke wrote:
> On 8/24/07, Bo Thorsen <bo@xxxxxxxxxxxxxxxxxxxxx> wrote:
> > Show us the code.
> here it is:
> 
> void MyThread::run() {
> 	qDebug("%s", Q_FUNC_INFO);
> 
> 	QTimer::singleShot(0, this, SLOT(init()));
> 
> 	// exec event loop
> 	exec();
> 
> 	// do cleanups
> 	cleanup();
> }
> 
> void MyThread::init() {
> 	// ... init a few variables
> 
> 	// Update Timer:
> 	updateTimer = new QTimer(this);
> 	connect(updateTimer, SIGNAL(timeout()), this, SLOT(doUpdate()));
> 	updateTimer->start(updateTimeout);
> }
> 
> void MyThread::cleanup() {
> 	qDebug("%s", Q_FUNC_INFO);
> 
> //	routeUpdateTimer->stop(); // <-- problem 1
> 
> //	delete routeUpdateTimer;  // <-- problem 2
> //	routeUpdateTimer = 0;
> }

But thats nt the timer you created in init(), the variable is named
differently. If thats not the problem: Does cleanup() get called at all?
how do you exit the event loop of your thread?

Andreas

-- 
 [ signature omitted ] 

Message 6 in thread

On 8/24/07, Andreas Pakulat <apaku@xxxxxx> wrote:

> But thats nt the timer you created in init(), the variable is named
> differently. If thats not the problem: Does cleanup() get called at all?
> how do you exit the event loop of your thread?

A mistake while preparing the code example :)

I start and stop my Thread with signals (button clicks) connected to the
start() and quit() slots the Thread.

Yes, cleanup() is called after exec() in run() returns.


Jens

-- 
 [ signature omitted ] 

Message 7 in thread

On a side note:

you dont really need to do this:
	routeUpdateTimer->stop(); // <-- problem 1
since the event loop is done anyways,

and you don't need to do this:
	delete routeUpdateTimer;  // <-- problem 2

since you gave the timer a parent:
	updateTimer = new QTimer(this);

so whenever "this" will be destroyed, the QObject system will automatically delete the Timer.
http://doc.trolltech.com/4.3/objecttrees.html

Cheers,
Peter

Message 8 in thread

On Friday 24 August 2007 10:27:47 Jens Luedicke wrote:
> On 8/24/07, Bo Thorsen <bo@xxxxxxxxxxxxxxxxxxxxx> wrote:
> > Show us the code.
>
> here it is:
>
> void MyThread::run() {
> 	qDebug("%s", Q_FUNC_INFO);
>
> 	QTimer::singleShot(0, this, SLOT(init()));
>
> 	// exec event loop
> 	exec();
>
> 	// do cleanups
> 	cleanup();
> }
>
> void MyThread::init() {
> 	// ... init a few variables
>
> 	// Update Timer:
> 	updateTimer = new QTimer(this);
> 	connect(updateTimer, SIGNAL(timeout()), this, SLOT(doUpdate()));
> 	updateTimer->start(updateTimeout);
> }
>
> void MyThread::cleanup() {
> 	qDebug("%s", Q_FUNC_INFO);
>
> //	routeUpdateTimer->stop(); // <-- problem 1
>
> //	delete routeUpdateTimer;  // <-- problem 2
> //	routeUpdateTimer = 0;
> }
>
>
> Jens

Seems you're hitting the bug described here: 
http://trolltech.com/developer/task-tracker/index_html?id=169376&method=entry

It was fixed in 4.3.1, which version of Qt are you using?


-- 
 [ signature omitted ] 

Message 9 in thread

Suppose you have:

class MyThread: public QThread {
  ...
  void run() {
    ...
    exec();
    ...
  }
  ...
};

Object of MyThread class is created in MainThread (unless you start 
thread from another one - not Main thread). The key point that 
everything you run before invoking
    QThread::exec()
in
    MyThread::run()
is supposed to be running in MainThread. On the other Communication 
between Thread and MainThread should be done via connections of Signals 
<-> Slots (the safest ones).
Event may be emitted in MainThread and will be put into a stack of 
Events Loop in Thread in case there is connection. Thus if there is 
already any events in Stack on QThread::exec() invocation - they will be 
processed first.

Thus solution: put some Event into Stack of Events, for example use 
external small class:


class ThreadSemaphore: public QObject
{
  Q_OBJECT

  signals:
     void started();

  public:
    // Constructor, Destructor (empty ones... no job is done)

    inline void start() { emit started(); }
};
 
----
MyThread::MyThread( ...)
{
  ...
  poThreadSemaphore_ =  new ThreadSemaphore();

  connect( poThreadSemaphore_, SIGNAL( started()),
                 this, SLOT( onStartedThread()) );
}

MyThread::~MyThread() { delete poThreadSemaphore_; }
...
void MyThread::run() {
  // Next line will emit signal in MainThread and Event will be kept in 
Thread Events stack unless exec() is invoked.
  poThreadSemaphore_->start();

  exec();

// Thread postprocessing
}

void MyThread::onStartedThread() {
// Start work that is supposed to be done inside thread having already 
Events loop invoked
// [note: don't forget to call quit() once you are done working with thread
}
...

Now QTimer is not needed any more.

Samvel

Jens Luedicke wrote:
> Hey,
>
> right now I'm using a singleShot Timer to run a initialization method
> once my QThread enters its event loop. Within this init() method I
> initialize an QTimer(this) object.
>
> The problem is: The QTimer keeps running after the QThread event loop quits.
> I can't stop and I can't delete the QTimer object from outside the
> event loop (after the exec() line in run())
>
> Any ideas?
>
> Jens
>
>   

--
 [ signature omitted ] 

Message 10 in thread

On 8/24/07, Samvel Khalatian <ksamdev@xxxxxxxxx> wrote:
> Suppose you have:
>
> class MyThread: public QThread {
>   ...
>   void run() {
>     ...
>     exec();
>     ...
>   }
>   ...
> };
>
> Object of MyThread class is created in MainThread (unless you start
> thread from another one - not Main thread). The key point that
> everything you run before invoking
>     QThread::exec()
> in
>     MyThread::run()
> is supposed to be running in MainThread. On the other Communication
> between Thread and MainThread should be done via connections of Signals
> <-> Slots (the safest ones).
> Event may be emitted in MainThread and will be put into a stack of
> Events Loop in Thread in case there is connection. Thus if there is
> already any events in Stack on QThread::exec() invocation - they will be
> processed first.

AFAICS this is the same as running an init slot via Single Shot once
the Thread Event Loop
runs. My Problem is starting and stopping QTimer's within the MyThread context:

From the docs:

"To start an event loop from a non-GUI thread, use QThread::exec(). Qt
uses the the timer's thread affinity to determine which thread will
emit the timeout() signal. Because of this, you must start and stop
the timer in its thread; it is not possible to start a timer from
another thread."


Jens

-- 
 [ signature omitted ]