添加链接
link管理
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接
Your browser does not seem to support JavaScript. As a result, your viewing experience will be diminished, and you have been placed in read-only mode . Please download a browser that supports JavaScript, or enable it if it's disabled (i.e. NoScript).

Hello everyone,
How do I perform an infinity function with an interval?
When I inherit QThread and override run() I call exec() inside it, but it blocks everything that comes after.

MyClass::MyClass():
    qDebug() << " MyClass() " << QThread::currentThread();
    moveToThread(this);
    start();
void MyClass::run(){
    qDebug() << "MyClass::run() " << QThread::currentThread();
    qDebug() << "before exec()";
    exec();
    for (int var = 0; var < 5; ++var) {
        emit emitMyClass("MyClass" + QString::number(i++));
        qDebug() << " Emit! " <<QThread::currentThread();
        QThread::sleep(5);
    qDebug() << "after exec()";

thanks in advance,

When I inherit QThread and override run() I call exec() inside it, but it blocks everything that comes after.

Exactly as documented.

You do not need a thread to do periodic execution of some action.

QTimer *timer = new QTimer(this);
connect(timer, &QTimer::timeout(), someQObject, &SomeQObjectClass::timeoutSlot());
timer->setInterval(5); // milliseconds
timer->start();

Whatever happens inside the slot needs to be short running. There is no loop in the slot. This object should maintain a run count (to replace var) and either stop the timer when 5 is reached, or reset the count to 0 etc.

@salvatore-proxy
Thanks @c-cardona ,
the example above of the for going from 0 to 5 was an example , also imagine it as a

while(1){
  doSOmethings

I need to periodically perform a function but in a separate thread, ie,
I have the main thread doing things, I need to create a new thread where within it I perform a function periodically, I have succeeded by overriding the run() method

void run(){
    init();
    while(true)
        periodicFunction();
        QThread::sleep(2);

this way it works but I don't have the event loop active via exec();

void run(){
    init();
    exec();   // Start event loop
    while(true)
        periodicFunction();
        QThread::sleep(2);

exec() after this instruction nothing is executed, only after calling exit() does the flow of the run() function resume;

timer = new QTimer(); timer->setInterval(1000); QObject::connect(timer, &QTimer::timeout, this, &MyClass::periodicFunction); timer->start(); exec(); // Start event loop

I used the run() method by also calling exec() so I have event loops to use signals and slots, but I have an internal timer that calls my run periodically, do you agree?

My needs are to:

  • launch a new thread that can handle slots and signals ( event loop is needed for this)
  • run in the new thread the slots connected to signals from other threads and periodically run a task that generates a signals to other threads
  • exec() starts an event loop just like you already do when calling app.exec() inside main(). This is the reason why it blocks.

    Overriding QThread::run() is the Java way to do multi-threading. Qt started moving away from this (and even the documentation does not teach this approach as the normal one anymore). The default implementation of run() will just call exec(). Instead, Qt promotes a worker object approach. Inherit from QObject and implement a slot (or just use a lambda if that is sufficient). The QTimer object would also then be created from another thread and then moved into the thread using QObject::moveToThread().

    You source should then look something like this:

    class MyClass : public QObject
    Q_OBJECT
    public slots:
      void periodicFunction() {...}
    //-----8<---------------------------------------------
    QThread *thread = new QThread();
    thread->start(); // could also be done later
    MyClass *obj = new MyClass();
    obj->moveToThread(thread);
    QTimer *timer = new QTimer();
    timer->setInterval(1000);
    QObject::connect(timer, &QTimer::timout, obj, &MyClass::periodicFunction);
    timer->moveToThread(thread);
    timer->start();
    

    If I'm not mistaken, even if you don't move the timer into the thread (but do move the instance of MyClass) it will work correctly. The timeout would then fire inside the main thread, but signal/slot connection will work across thread boundaries. And because obj is located inside the thread (because of moveToThread()) the slot will be executed with the separate thread.

    If you just want a simple function, you could also connect to a lambda instead:

    QObject::connect(timer, &QTimer::timeout, [](){ ...});
    

    However, the lambda is not located in any specific thread. This would mean you have to move the timer again into the thread (whereas before this was optional).

    You could, however, provide a context object for the lambda. Maybe this would start execution of the lambda inside the corresponding thread even if the time lives inside the main thread:

    QObject::connect(timer, &QTimer::timeout, thread, [](){ ... });
    

    We heavily rely on plain QThreads (without inheritance) in our software. Usually, we don't need repeated calls. An easy start is QThread::create([]() {...})->start();. But, you need to make sure to delete the thread itself at the end. For a worker thread you can use QMetaObject::invokeMethod(thread, []() {...}); for a one-time slot to be handled by a running QThread.

    @SimonSchroeder said in QThread infinite loop:

    If I'm not mistaken, even if you don't move the timer into the thread (but do move the instance of MyClass) it will work correctly. The timeout would then fire inside the main thread, but signal/slot connection will work across thread boundaries

    Question: Suppose the main thread is (perhaps incorrectly) "blocked" (or busy doing some computation). In that case although the signal is connected "queued across thread" would the signal not be acted on/the slot get queued for execution in the thread at the instant of the emit, would it have to wait till the next time the main thread's event loop is hit (whenever that might be)?

    @JonB said in QThread infinite loop:

    would it have to wait till the next time the main thread's event loop is hit

    From my understanding: yes.

    @SimonSchroeder said in QThread infinite loop:

    //-----8<---------------------------------------------
    QThread *thread = new QThread();
    thread->start(); // could also be done later
    MyClass *obj = new MyClass();
    obj->moveToThread(thread);
    QTimer *timer = new QTimer();
    timer->setInterval(1000);
    QObject::connect(timer, &QTimer::timout, obj, &MyClass::periodicFunction);
    timer->moveToThread(thread);
    timer->start();
    

    Multithreading is hard! The timer->start() should come before timer->moveToThread(). I would also establish the connection from the QTimer instance to MyClass instance before moving the later. It's paranoia in this case, but prevents connecting to deleted objects in some realistic scenarios.