Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. General and Desktop
  4. How to update QWidget content from a background thread lambda.
Forum Updated to NodeBB v4.3 + New Features

How to update QWidget content from a background thread lambda.

Scheduled Pinned Locked Moved Unsolved General and Desktop
5 Posts 2 Posters 882 Views 1 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • M Offline
    M Offline
    mikhail_kr
    wrote on last edited by mikhail_kr
    #1

    Hi

    I have a class MyWorkerClass which use a separate thread to perform calculations. I can specify lambda callback to be notified on updates like this:

    MyWorkerClass::instance().setCallback( | |() { printf("completed"); });

    I also have a QWidget subclass instance which displays data.
    I want to update the content of my widget from the lambda expression above.

    Looks like I can do this that simple:

    MyWorkerClass::instance().setCallback( | this | () { onUpdate(); });

    But if user decide to close the window with my widget - the lambda will try to call method of already deleted class instance.
    Of course I can zero the lambda in the destructor of my QWidget subclass. But this will result in race conditions.

    What is the right way to update my QWidget from the lambda ?

    kshegunovK 1 Reply Last reply
    0
    • M mikhail_kr

      Hi

      I have a class MyWorkerClass which use a separate thread to perform calculations. I can specify lambda callback to be notified on updates like this:

      MyWorkerClass::instance().setCallback( | |() { printf("completed"); });

      I also have a QWidget subclass instance which displays data.
      I want to update the content of my widget from the lambda expression above.

      Looks like I can do this that simple:

      MyWorkerClass::instance().setCallback( | this | () { onUpdate(); });

      But if user decide to close the window with my widget - the lambda will try to call method of already deleted class instance.
      Of course I can zero the lambda in the destructor of my QWidget subclass. But this will result in race conditions.

      What is the right way to update my QWidget from the lambda ?

      kshegunovK Offline
      kshegunovK Offline
      kshegunov
      Moderators
      wrote on last edited by
      #2

      This is wrong on so many levels.

      Firstly, you're introducing a global state for no reason - yes, singletons are pretty stupid and useless.

      Secondly, you're assuming that you can call whatever you like from one thread to the next. There's such a thing called race condition, you can't just call functions around. A thread is a function, that function has a call stack, calling something from one call stack into the next one unless specific protection measures are taken (i.e. guaranteeing thread safety) is a no-no.

      Thirdly, you shall not touch anything GUI from a thread different than the GUI one (a consequence of 2). Moreover, GUI calls can't be made thread-safe, and are not reentrant. Meaning not only can't you call methods into the GUI, but you also can't create GUI objects into a separate thread.

      Finally, the solution is: to have a worker object, which is moved in the proper thread by means of QObject::moveToThread. This worker object is then to fire a signal, which is connected to the relevant GUI objects' slots and updates the GUI elements by queuing an event over the main thread's event loop (which is the default behaviour).

      Read and abide by the Qt Code of Conduct

      M 1 Reply Last reply
      5
      • M Offline
        M Offline
        mikhail_kr
        wrote on last edited by mikhail_kr
        #3

        "Secondly, you're assuming that you can call whatever you like from one thread to the next..."
        Thank you very much for the detailed explanation! I will take it into account.

        @kshegunov said in How to update QWidget content from a background thread lambda.:

        Finally, the solution is: to have a worker object,

        You mean I should rewrite a third-party code with QThread and QObject::moveToThread ?
        Is there any solutions without rewriting 3rd party code ?

        1 Reply Last reply
        0
        • kshegunovK kshegunov

          This is wrong on so many levels.

          Firstly, you're introducing a global state for no reason - yes, singletons are pretty stupid and useless.

          Secondly, you're assuming that you can call whatever you like from one thread to the next. There's such a thing called race condition, you can't just call functions around. A thread is a function, that function has a call stack, calling something from one call stack into the next one unless specific protection measures are taken (i.e. guaranteeing thread safety) is a no-no.

          Thirdly, you shall not touch anything GUI from a thread different than the GUI one (a consequence of 2). Moreover, GUI calls can't be made thread-safe, and are not reentrant. Meaning not only can't you call methods into the GUI, but you also can't create GUI objects into a separate thread.

          Finally, the solution is: to have a worker object, which is moved in the proper thread by means of QObject::moveToThread. This worker object is then to fire a signal, which is connected to the relevant GUI objects' slots and updates the GUI elements by queuing an event over the main thread's event loop (which is the default behaviour).

          M Offline
          M Offline
          mikhail_kr
          wrote on last edited by
          #4

          @kshegunov said in How to update QWidget content from a background thread lambda.:

          updates the GUI elements by queuing an event over the main thread's event loop (which is the default behaviour).

          Is it safe to post an event from my lambda like this:

          MyWorkerClass::instance().setCallback( | | () {
          QCoreApplication::postEvent(NULL /* ptr to the receiver */, new MyEvent);
          });

          and then handle the event in my widget class ? Or the receiver must be not null and I have to specify pointer to the QWidget subclass instance? (The documentation does not say anything about the receiver parameter can be null or not)
          If I have to specify the pointer - It can become a dangling pointer. How to avoid this?

          kshegunovK 1 Reply Last reply
          0
          • M mikhail_kr

            @kshegunov said in How to update QWidget content from a background thread lambda.:

            updates the GUI elements by queuing an event over the main thread's event loop (which is the default behaviour).

            Is it safe to post an event from my lambda like this:

            MyWorkerClass::instance().setCallback( | | () {
            QCoreApplication::postEvent(NULL /* ptr to the receiver */, new MyEvent);
            });

            and then handle the event in my widget class ? Or the receiver must be not null and I have to specify pointer to the QWidget subclass instance? (The documentation does not say anything about the receiver parameter can be null or not)
            If I have to specify the pointer - It can become a dangling pointer. How to avoid this?

            kshegunovK Offline
            kshegunovK Offline
            kshegunov
            Moderators
            wrote on last edited by
            #5

            @mikhail_kr said in How to update QWidget content from a background thread lambda.:

            Is it safe to post an event from my lambda like this

            It is safe, but you need to pass the pointer to the object which is going to receive the event. nullptr isn't acceptable.

            If I have to specify the pointer - It can become a dangling pointer. How to avoid this?

            Generally not an easy thing to do. You can try QPointer, but I'm not 100% if it's acceptable across threads.

            Read and abide by the Qt Code of Conduct

            1 Reply Last reply
            1

            • Login

            • Login or register to search.
            • First post
              Last post
            0
            • Categories
            • Recent
            • Tags
            • Popular
            • Users
            • Groups
            • Search
            • Get Qt Extensions
            • Unsolved