QThreads , QObject and sleep function
Asked Answered
I

4

8

The problem I encountered is that I decided to implement QThreads the way they are supposed to, based on numerous articles:
https://www.qt.io/blog/2010/06/17/youre-doing-it-wrong
http://mayaposch.wordpress.com/2011/11/01/how-to-really-truly-use-qthreads-the-full-explanation/

and issue at hand is that since the algorithm is run in separate QObject (wrapped in QThread). How can I call out something like Thread::Sleep or smth .. Any ideas?

A small description of the software. Basically my application solves TSP (Traveling salesman problem). As the search goes along, it saves all the states in the history as frames ..(like visual frames). The search algorithms will be run on one thread. Main thread is handling with the GUI. Then there is the Mediaplayer like thread which tells Main thread what frame to display on screen. So where does the sleep come in ? In gui there is a slider that user can use to fast forward or go in normal pace.. that slider tells via signal slot to Mediaplayer thread to go faster or slower.

Inspect answered 27/5, 2012 at 19:4 Comment(7)
Just call it? Please post the code you have, and explain what's not working with it.Lietman
@Mat: the problem is that Qt made sleep() a protected member of the QThread class. And so, when you write your thread as a slot hooked up to a QThread's signal, you don't have direct access to itGujral
Ah, ok. Well you can just subclass and "rexport" the function, but why are you trying to sleep anyway? Timers (or wait conditions) are often a better solution. If you explained the problem you're trying solve, you'd probably get more useful information.Lietman
@Mat: why does the sleep function exist? Because sometimes, sleep is actually the correct solution...Gujral
@jalf: sure. But if a framework you're using forcibly prevents you from using those functions directly, and provides a bunch of other tools to handle many (but indeed not all) cases where you'd want to "spend some time doing nothing", maybe there are better ways of doing that within the framework?Lietman
@jalf: you've made your point quite cleary about the QThread API. Mine is that if you're using an event-driven framework, sleep is often the wrong thing to want to be doing in the first place. There's nothing fundamentally wrong with using std::thread in a Qt app if you don't want/need the event-driven model and the crappy thread class that comes with it.Lietman
The QThread class is hardly crappy. What's your problem with it? There are some genuine uses for a thread that's not event driven, and then you derive from QThread and reimplement void run(). But the default way of doing things should be always by having asynchronous, run-to-completion code in slots in a QObject. See, for example, I Hate RTOSes by Miro Samek embeddedgurus.com/state-space/2010/04/i-hate-rtoses. Then, when benchmarking shows that the code you want to run is CPU starved (whether by the GUI thread, or the thread it's already in), you move it to a new thread.Briar
G
7

What we've done is basically something like this: (written by memory, as I don't have our code checked out on this computer)

class Sleeper : public QThread {
public:
   void sleep(int ms) { QThread::sleep(ms); }
};

void sleep(int ms);

// in a .cpp file:
static Sleeper slp;

void sleep(int ms) {
    slp.sleep(ms);
}

The key is that the QThread::sleep function causes the calling thread to sleep, not the threaf represented by the QThread instance. So just create a wrapper which calls it via a custom QThread subclass.

Unfortunately, QThread is a mess. The documentation tells you to use it incorrectly. A few blog posts, as you've found, tell you a better way to do it, but then you can't call functions like sleep, which should never have been a protected thread member in the first place.

And best of all, even no matter which way you use QThread, it's designed to emulate what's probably the worst thread API ever conceived of, the Java one. Compared to something sane, like boost::thread, or even better, std::thread, it's bloated, overcomplicated and needlessly hard to use and requiring a staggering amount of boilerplate code.

This is really one of the places where the Qt team blew it. Big time.

Gujral answered 27/5, 2012 at 19:11 Comment(7)
You're adding a synchronous (blocking) construct into a fundamentally asynchronous code that must be written in run-to-completion way. It's bad advice. There is a reason why sleep() is protected. You should never use it. It should be private for all I care.Briar
@KubaOber: A thread is not "fundamentally asynchronous". It is not a task, it is not a thread pool or anything like that. And sleep is sometimes useful. What if I want to call sleep on the main thread? Are you going to argue that the main thread is "fundamentally asynchronous code"?Gujral
In a GUI Qt application, the main (GUI) thread is supposed to execute short, run-to-completion pieces of code that quickly return to the event loop. That's how event driven frameworks are designed. If you do something else, you can't expect decent application behavior from the viewpoint of the user. Sure you can sleep all you want, but the application will feel like crap. It's not a law of nature, it's just a choice between software that performs well and software that sucks. Your choice.Briar
@KubaOber: sure, the GUI thread should probably not sleep (at least not while it's in the event loop), but where did I say otherwise? I'm not even talking about GUI applications specifically. but about applications which use QThreads. You are making a universal statement that NO thread should ever sleep, ever, under any circumstances. Which is nonsense.Gujral
If you're sleeping in a QThread, that thread cannot process events for this nor any other QObjects. It becomes a single-use thread. For peak performance, you shouldn't have more than say 2 threads per each core available on the system. Of course there are widely deployed piece-of-crap APis, like many database APIs that are completely synchronous and internally block on network sockets/pipes/unix sockets. Using a dedicated thread for those is an unfortunate necessity, but it's not good design, it's a workaround for someone else's crap.Briar
I also cannot exactly fathom what sort of an application would have much use for sleeping in the main thread, except perhaps for cron/anacron style scheduled executioner. Do note that by sleeping I mean uninterruptible sleep. Using, for example, Unix select() with a timeout is an interruptible sleep, Qt's QEventDispatcher does the same thing in a platform-specific way.Briar
Yes, if you're sleeping in a QThread it cannot process events. Not every thread needs to process events. Not every thread has an event loop. Some threads are single-use threads. So yeah, if you can't fathom what sort of application would need to sleep in a thread (not necessarily the main one, but any thread), then, well, good for you. In that case, you live in a simpler world than some of us. :)Gujral
O
4

The simple answer: you're not supposed to block in asynchronous, run-to-completion code -- every event handler and slot implementation in a QObject is supposed to do its job and return, as soon as possible. It's not supposed to do any sort of busy waiting or sleeping. For more ranting along this line, see Miro Samek's I hate RTOSes.

For a much better implementation that follows from the above, see this answer instead. Macro trickery that follows below is best left to the poor souls stuck with C.

I've attached an example of how to do it the right way at least from the point of view of what the code does. If you want a real implementation, look no farther than Boost's stackless coroutines.

The macro trickery is syntactic sugar - it makes the technique more palatable (Boost does it better than I do below). Whether you use macros or write out the methods explicitly, is up to you. The syntax is not what is claimed to be the "right way" of doing it. I'm not the only one to use such preprocessor trickery. Missing is support nested function calls, and multiple "threads" of run-to-completion execution within a QObject. The example shows code for only one "thread" and only one level of async function calls. Stackless Python takes this to the logical conclusion.

You'll see this pattern in all of your code if you write it in an asynchronous way. The SLEEP macro is syntax sugar to help make the code easier to follow. There's no truly clean way to write it without a hacky macro in C++ where the syntax wouldn't be overbearing. Even as of C++11, the language has no built-in support for yield. See Why wasn't yield added to C++0x?.

This is truly non-blocking code, you'll see that the periodic timer event fires while you're "asleep". Do note that this cooperative multitasking has a much lower overhead than thread/process switches done by the OS. There's a reason why 16 bit Windows application code was written this way: it performs quite well, even on meager hardware.

Note that this code does not need a QThread, and in fact doesn't use a QThread, although if you'd move the object to a high priority thread, the delays will have lower spread.

The Qt timer implementation is clever enough to decrease the timer tick period on Windows, if the period is "short". You can use the platform-specific code I show below, but it should be discouraged. On Qt 5, you'd simply start a Qt::PreciseTimer timer. Do note that on pre-Windows 8 systems you're trading off power consumption and a slightly higher kernel overhead for performance here. Windows 8, OS X (xnu) and modern Linux are tickless and don't suffer from such performance degradation.

I should acknowledge the clear preprocessor abuse direction from Creating C macro with ## and __LINE__ (token concatenation with positioning macro).

Similarly to the SLEEP() macro, you can also implement a GOTO() macro, to allow you having simple finite state machines that are written in an easier-to-follow blocking code style, yet are asynchronous behind the scenes. You can have ENTER() and LEAVE() macros to implement actions to be done on state entry and exit, etc, yet the code can look entirely like a straight-coded blocking-style function. I've found it quite productive, and easier to follow than code that lacks any syntactic sugarcoating. YMMV. In the end, you would have something that's on the way to UML statecharts, but with less overhead (both runtime and code-text-wise) than QStateMachine-based implementations.

Below is the output, the asterisks are periodic timer ticks.

doing something
*
*
*
*
*
*
*
*
*
*
slept, a=10
*
*
*
*
*
slept, a=20
*
*
slept, a=30
*
slept, a=40
#sleep.pro
QT       += core
QT       -= gui
TARGET = sleep
CONFIG   += console
CONFIG   -= app_bundle
TEMPLATE = app
SOURCES += main.cpp
//main.cpp
#ifdef Q_WS_WIN
#include <windows.h>
#endif
#include <cstdio>
#include <QtCore/QTextStream>
#include <QtCore/QObject>
#include <QtCore/QBasicTimer>
#include <QtCore/QTimer>
#include <QtCore/QCoreApplication>

QTextStream out(stdout);

// this order is important
#define TOKENPASTE2(x,y) x ## y
#define TOKENPASTE(x,y) TOKENPASTE2(x,y)
#define SLEEP(ms) sleep(ms, &SLEEPCLASS::TOKENPASTE(fun, __LINE__)); } void TOKENPASTE(fun, __LINE__)() {

class Object : public QObject
{
    Q_OBJECT
    #define SLEEPCLASS Object // used by the SLEEP macro
public:
    Object() {
        QTimer::singleShot(0, this, SLOT(slot1()));
        periodic.start(100);
        connect(&periodic, SIGNAL(timeout()), SLOT(tick()));
    }
protected slots:
    void slot1() {
        a = 10; // use member variables, not locals
        out << "doing something" << endl;
        sleep(1000, &Object::fun1);
    }
    void tick() {
        out << "*" << endl;
    }

protected:
    void fun1() {
        out << "slept, a=" << a << endl;
        a = 20;
        SLEEP(500);
        out << "slept, a=" << a << endl;
        a = 30;
        SLEEP(250);
        out << "slept, a=" << a << endl;
        a = 40;
        SLEEP(100);
        out << "slept, a=" << a << endl;
        qApp->exit();
    }

private:
    int a; // used in place of automatic variables

private:
    void sleep(int ms, void (Object::*target)()) {
        next = target;
        timer.start(ms, this);
    }
    void timerEvent(QTimerEvent * ev)
    {
        if (ev->timerId() == timer.timerId()) {
            timer.stop(); (this->*next)();
        }
    }
    QTimer periodic;
    QBasicTimer timer;
    void (Object::* next)();
};

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);
    Object o1;
#ifdef Q_WS_WIN
   timeBeginPeriod(1); // timers will be accurate to 1ms
#endif
    return a.exec();
}

#include "main.moc"
Opium answered 31/5, 2012 at 23:25 Comment(1)
I'm having a hard time deciding if this is genius, evil, or evil genius. It's definitely very clever, but I get the ick feeling knowing that a macro is breaking up one method into many.Nochur
J
4

I agree with jalf. I have a thread that acts as a sort of DBUS daemon and needs to listen to messages forever. Two things to mention:

jalf has

void sleep(int ms) { QThread::sleep(ms); }

But this is NOT MILLISECONDS! QThread::sleep() takes seconds. Also, if one is to take this approach, he must also include the QThread lib anyway, so it might be easier to just make the call like this:

QThread::sleep(seconds);

directly in the code. That way there isn't an extra header file. I ran this and it also works as jalf explained. (putting the calling thread to sleep.)

Jaredjarek answered 22/5, 2014 at 10:20 Comment(1)
No separate lib even, iirc -- it's all in QtCore :)Errecart
H
0

For Qt 4.8.0 (the version I'm using), QThread::sleep, QThread::msleep and QThread::usleep have been made public so you can just call them directly. In earlier Qt versions, they were static protected.

e.g. QThread::sleep(5); // sleep for 5 seconds

Handsaw answered 18/4, 2018 at 3:50 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.