Re: Using QTimer in a QThread
Maybe we misunderstand each-other. I'm trying to proof that thread shouldn't be moved to itself!
Here is test code (stupid example but it works):
Code:
#include <QThread>
#include <QApplication>
#include <QPushButton>
#include <QTimer>
int main(int argCount, char* args[])
{
timer.setInterval(2000);
timer.moveToThread(&thread);
// thread.moveToThread(&thread); // this shouldn't be done
QObject::connect(&button,
SIGNAL(clicked
()),
&thread, SLOT(start()));
QObject::connect(&button,
SIGNAL(clicked
()),
&timer, SLOT(start()));
QObject::connect(&timer,
SIGNAL(timeout
()),
qApp, SLOT(quit()));
button.show();
app.exec();
thread.exit();
thread.wait(1000);
return 0;
}
Program terminates after 2 second push button was pressed.
Uncomment line 15 and program will not terminate 2 seconds after button was pressed you have a dead lock (checked on Ubuntu 10.04).
Re: Using QTimer in a QThread
@wysota
As usually, you state a radical opinion in a radical way. I'm curious what your approach would be to solve the task as stated above, that a steady high frequency communication (100Hz) has to be maintained while the CPU can be potentially maxed out at times with other tasks. RTOS is not an option, the target OS is Windows. Maybe it's a useful piece of information that one iteration of the communication takes between 2 and 3 milliseconds and it barely needs any CPU, since most of it is I/O time.
Another advantage I see in threads is that often there is more than one core and while one core is struggling with the gui, the other core can still maintain the steady communication frequency. This would not be possible with only one process.
Re: Using QTimer in a QThread
Hello Cruz,
I'm running several 1-2ms precise threads under windows. What significantly improved matters is to lock the threads to specific cpu cores. By default windows "pushes them around" quite a bit, with negative influence on timing precision.
Code:
#ifdef Q_WS_WIN
# include "windows.h"
#endif
#ifdef Q_OS_UNIX
# include "unistd.h"
# include "sys/syscall.h"
# include <sys/types.h>
# include <sys/time.h>
# include <sys/statfs.h>
# include <stdio.h>
# include <sched.h>
#endif
void QntsHPC::setCpuAffinityMask(quint32 coreMask)
{
// check if there are multiple cores at all
if (QThread::idealThreadCount() >
1) {
# ifdef Q_OS_WIN
SetThreadAffinityMask(GetCurrentThread(),coreMask);
# endif
# ifdef Q_OS_UNIX
//sched_setaffinity(gettid());
int proc_num = (int)(long)coreMask;
cpu_set_t set;
CPU_ZERO( &set );
CPU_SET( proc_num, &set );
sched_setaffinity( syscall(SYS_gettid), sizeof( cpu_set_t ), &set );
# endif
}
}
The mask is a bit-vector, see documentation for SetThreadAffinityMask.
You probably will need only a subset of the linux includes for this. But no matter, your target is windows anyway :->
HIH
Johannes
Re: Using QTimer in a QThread
@Marek:
this is not a dead lock, but a blocking call which never returns.
A dead lock is when two or more processes are each waiting for the other to release a resource, or more than two processes are waiting for resources in a circular chain.
In your example, since your thread didn't start, it is not processing the events it got, or events have no where to go.
When you perform a moveToThread on the QThread object, that is all you do - you move a QThread object to the thread it started (if it did start a new thread).
I don't see for what it could be good, but you need to understand the implications.
"shouldn't be done" is an assertion that is worth very little if you don't explain why, or under what conditions.
The only thing I am not sure about in the way your example works, is, that since you didn't call start() on the thread, there should be no "other thread", thus I am not sure what moveToThread() does in a case where the thread didn't start.
That is the only point I am not quite sure how the internals of moveToThead work.
@wysota:
If you are reading this maybe you can answer what happens if you move to a thread that hasn't been started yet?
I don't have Qt here.
Re: Using QTimer in a QThread
@Johannes
Thanks, I will try this! Did you evaluate how this technique works on Linux? While I am currently bound to Windows, my long term goal is to write something that works on both, Windows and Linux.
Re: Using QTimer in a QThread
I measured the min/max/stddev of QThread::msleep intervals with the performance counter only under windows. I did not run the same tests on linux, because on my dev-machine it runs only virtually. But timing critical network connections between the virtual linux machine and other computers in the network seemed to work with good latencies, so I stopped tweaking.
Be aware, that if you use only msleep and no timers with intervals smaller than 20ms you will have to increase the windows timer resolution for msleep to work correctly.
See: http://www.qtcentre.org/threads/4031...340#post185340
Johannes
Re: Using QTimer in a QThread
Quote:
Originally Posted by
high_flyer
Common witek, so what are you saying?
You should not implement tasks that need time resolutions in ms range in non RTOS?
I would say you should not aim to have precise timing on a system that can't give it to you.
Quote:
I am sure you, just as I have, made many such usages of threads that are "real time like" under windows/linux.
There is a difference between real-time-like and expectations to have a slot called at exactly 10ms intervals. I'd say such expectations are not required in most cases and there using a regular system is fine. I would like to know why OP wants to have precisely 10ms intervals.
Re: Using QTimer in a QThread
Quote:
Originally Posted by
Cruz
I'm curious what your approach would be to solve the task as stated above, that a steady high frequency communication (100Hz) has to be maintained while the CPU can be potentially maxed out at times with other tasks.
I would use a real time operating system or rethink my design.
Quote:
RTOS is not an option, the target OS is Windows.
If it's not an option then just forget it and do something that doesn't require such rigid timing. If you can live with your app working properly "most of the time" or "sometimes" then just go ahead and keep your current approach. Just don't be surprised that if your system decides to do something besides scheduling your thread (say... defragment your harddisk) you will loose your "steady pace". People use real-time operating systems not because they are fun to use but because they are required to reach their goals. On a non-RT OS there is simply no way to force your OS to wake you up at constant intervals. You can use multimedia timers, bind process to a cpu or do anything else you want but this will give you no guarantees. You will be "close to 10ms" "usually" or even "most of the times" but not "always". If you can live with that then go ahead. But if you can live with that then maybe you don't need it after all.
If your robot was performing some kind of surgery or space exploration-thingy I would surely not put my life in its hands if it required time guarantees and you were using regular Windows to obtain it.
Quote:
Another advantage I see in threads is that often there is more than one core and while one core is struggling with the gui, the other core can still maintain the steady communication frequency. This would not be possible with only one process.
Unless you have more cores than processes running in your system this is completely meaningless in this particular situation.
Quote:
Originally Posted by highflyer
@wysota:
If you are reading this maybe you can answer what happens if you move to a thread that hasn't been started yet?
I don't have Qt here.
Nothing happens. It (the object in question) can't process events (including slots) until the thread event loop is started. Similarily it can't process events (and slots) after the thread event loop is stopped. Besides this is just bad design. It's like you were driving a car using remote control sitting in the driver's seat of the very same car.
Re: Using QTimer in a QThread
Quote:
Nothing happens. It (the object in question) can't process events (including slots) until the thread event loop is started.
This is clear, but its not what I asked.
moveToThread() takes a QThread pointer.
The QThread object it self does exist, and its thread affinity is the thread in which it was created.
I would think that moveToThread() "moves" the calling object to the actual thread the QThread object started. (which is what happens if QThread created a thread)
But if no thread has been started, where does moveToThread() move the object to? (as in Marek's examples).
Does it mean that once an object has been 'movedToThread()' that it will "complete" the moving once the thread has been created with start()?
Quote:
Besides this is just bad design.
Ofcourse, but I still would like to understand it.
Re: Using QTimer in a QThread
Quote:
Originally Posted by
high_flyer
I would think that moveToThread() "moves" the calling object to the actual thread the
QThread object started. (which is what happens if
QThread created a thread)
But if no thread has been started, where does moveToThread() move the object to? (as in Marek's examples).
In reality what happens is that the object is checked for pending events and if such are found they are taken out of the event loop of the "old" thread and inserted into the event loop of the "new" thread. The event loop exists (it's actually an instance of QAbstractEventDispatcher that is keyed with a pointer to QThread) it's just not running. So the move suceeds.
Quote:
Does it mean that once an object has been 'movedToThread()' that it will "complete" the moving once the thread has been created with start()?
More likely when you call QThread::exec(). But this doesn't change the fact that after the thread event loop stops and run() returns there is no way to call any slots in the QThread object since it lives in a thread that doesn't process events anymore (so it can't call slots) and you can't push the object to the main thread because there is no worker thread context anymore to invoke the push. Similarily you have no control over what happens before you start the thread event loop.
Re: Using QTimer in a QThread
The discussion has drifted off here. The original question why a timer started in a thread appears to run in the main thread. And one of the issues pointed out (the reason for which is still unexplained!) is that a thread shouldn't handle it's own events.. A clean way to use a timer in a thread was suggested like this:
Code:
{
Q_OBJECT
public:
public slots:
void tick();
};
{
connect(t, SIGNAL(timeout()), this, SLOT(tick()));
}
void TestClass::tick()
{
qDebug() << currentThreadId() << "tick()";
}
// and somewhere
TestClass *object = new TestClass(); // can't pass parent!!!!!!
object->moveToThread(thread);
thread->start();
However, if not a QTimer, but a while and sleep method is used, this code changes to:
Code:
{
TestClass testClass;
}
Thread::Thread()
{
testClass.moveToThread(this);
start();
}
Thread::run()
{
forever
{
testClass.tick();
}
}
main
{
Thread rhread;
... do mainy things...
}
The problem I have with this construction is that now TestClass is buried inside the QThread wrapper. When signals needs to be emitted from main to TestClass, some kind of a hack needs to be used because TestClass is unknown in main. This is not the case, however, if TestClass IS a QThread and is moved to its own thread. So how can you solve this elegantly without moving the thread to itself?
Re: Using QTimer in a QThread
You either expose a getter that fetches a pointer to the object in the thread class or you provide a setter to set the object before the thread is executed or you embed the thread object in the TestClass object instead of embedding the TestClass object inside the thread object.
Re: Using QTimer in a QThread
Quote:
Originally Posted by
wysota
...or you embed the thread object in the TestClass object instead of embedding the TestClass object inside the thread object.
But then how does the thread call the tick() method of TestClass?
Re: Using QTimer in a QThread
For completeness, like this it works:
Code:
{
signals:
void tickOut();
}
Thread::Thread()
{
start();
}
Thread::run()
{
forever
{
emit tickOut();
msleep(10);
}
}
class TestClass
{
Thread thread;
public slots:
void tickIn();
}
TestClass::TestClass
{
moveToThread(&thread);
connect(&thread, SIGNAL(tickOut()), this, SLOT(tickIn()));
}
Is this ok? No hack or anything?
Re: Using QTimer in a QThread
It's not fine. You have a static time delay which means your real delay depends on how long it takes processEvents() to complete its work. The delay should be dynamically adjusted or it should be done using a timer. I don't see how calling sleep would be better than using a timer.
Re: Using QTimer in a QThread
The parameter to sleep is adjusted. I omitted it to simplify the code, because what I was asking about is if the construction is ok.
I looked at the steadiness of the QTimer based approach and the dynamically adjusted sleep approach and found the latter to be smoother.
Re: Using QTimer in a QThread
How did you "look" at it?
3 Attachment(s)
Re: Using QTimer in a QThread
I "looked" at it by "plotting" the iteration times produced by the dynamic sleep approach and the QTimer approach. I measured the iteration times using high performance counters on Windows. The following two plots show the different behaviors of the two approaches. Clearly, the QTimer based iterations are much more noisy.
Attachment 6280 Attachment 6281
I also "looked" at the effect of starting the thread in time critical instead of normal mode, and what happens if the cpu is stressed. The next plot shows the results of a series of 8 experiments. The 8 experiments are all combinations of dynamic sleep or QTimer, thread was started in time critical mode or not, and if the cpu was stressed or not. Red bars show dynamic sleep, blue bars show QTimers, each with mean and standard deviation "calculated" over 5 minutes runtime. I was aiming at an iteration time of 12 milliseconds. In the cpu stress experiments, both cores of my cpu were tortured by Prime95.
Attachment 6279
Re: Using QTimer in a QThread
How did you eliminate the influence of external conditions on the test you performed? Did you also do any stress testing? QTimer will show some variation because the resolution of timers used with it is usually greater than 1ms, especially on Windows. sleep() shouldn't suffer from such problems as it probably relies on capabilities of the scheduler. Also bear in mind both these approaches will fail if something (processEvents) occupies your app for the whole (or almost whole) desired interval or if something prevents the scheduler from running at the exact demanded point in time. You simply can't overcome this without RTOS.