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. [SOLVED] Accessing objects living in another (running) thread in a thread-safe way
Forum Updated to NodeBB v4.3 + New Features

[SOLVED] Accessing objects living in another (running) thread in a thread-safe way

Scheduled Pinned Locked Moved General and Desktop
14 Posts 5 Posters 8.6k 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.
  • S Offline
    S Offline
    Sigsegv
    wrote on last edited by
    #1

    I have 2 threads: a GUI thread and a worker thread.

    The worker thread will be writing values to a list for several seconds. Meanwhile, I would need to read and remove values from the list from the GUI thread while the working thread is still running.

    I suppose I could use a direct connection signal for the remove operation (although I'm not sure if that would be considered as a good solution) but the real problem is the reading operation.

    I would need to read values from the list (living in the still-busy worker thread) and process them right away within the GUI thread, so I can't use queued connection signals since they would be blocked until the completion of the working thread. I can't use direct connection signals either, since the reading operations are executed within a larger method that can't be interrupted to process incoming signals. Finally, I can't find any suitable way to use a mutex since the writing and reading operations are executed within different methods.

    Any ideas will be appreciated. Thanks in advance.

    1 Reply Last reply
    0
    • D Offline
      D Offline
      dvb0222
      wrote on last edited by
      #2

      Here is a slightly different pattern which might suit what you want to achieve.

      I am guessing that you want to have the worker thread read or generate some objects, and then add them to a list which will be read and displayed by an object on the GUI thread

      Instead of creating a list object for this, how about just having the method on the worker thread post events to the receiver object (on the GUI thread). This way the event queue of the GUI thread serves the purpose of your list. You can post an event to an object on another thread using http://doc.qt.io/qt-5/qcoreapplication.html#postEvent. Note that this static method is thread safe.

      Now all you need to do is uniquely identify your events with a new event type, subclass QEvent to contain the data you want to send, and implement http://doc.qt.io/qt-5/qobject.html#event on the object in the GUI thread to consume the events.

      Read about the event system here: http://doc.qt.io/qt-5/eventsandfilters.html


      David Van Beveren
      Oak Park Technology Corp.
      Malibu, California
      vbdavid@gmail.com

      1 Reply Last reply
      1
      • C Offline
        C Offline
        ckakman
        wrote on last edited by
        #3

        Hi,

        I think your problem is to modify a list by the thread simultaneously without waiting one of the modifying agents to finish its job.

        I can think of two solutions that may interest you besides the one proposed by dvb0222:

        Don't use a worker thread: Whatever triggers the worker thread to start adding new items to the list for several seconds, can trigger the process in the GUI thread the as well. Since you don't want to block the GUI thread so that the application becomes unresponsive, you may use QCoreApplication::processEvents() creatively so that the items are added to the list one by one while you also read and remove items one by one.

        Don't modify the list in the worker thread: Send the value objects to GUI thread and process it there. If the objects are expensive to copy, use a shared pointer or make the value object explicitly shared if you care for aesthetics. Here you may also need some creative QCoreApplication::processEvents() usage since you want to interleave add and read/remove operations.

        1 Reply Last reply
        0
        • S Offline
          S Offline
          Sigsegv
          wrote on last edited by
          #4

          Thank you for your replies, but I fail to see how can I use event processing to receive reading values right away. In my app the user can trigger key events which need to read values from the list (and process them). However, should the readings be returned using events (or signals, for that matter), I don't see how can I receive demanded values without exiting the current method (in which the readings have been demanded).

          1 Reply Last reply
          0
          • C Offline
            C Offline
            ckakman
            wrote on last edited by
            #5

            Hi,

            It is really difficult to understand one's problem when there is no code but general and rather vague description of the issue. Your last response doesn't ring a bell for me because I don't know your application. You haven't shared enough for us to understand your assumptions and constraints.

            • Why can't you read the list when the user triggers a key event?
            • What does it mean "to return a value" when you can just "show" a value on the UI when the user clicks a button?
            • Why processing the list and populating the list must be on different threads?
            • Why can't you send the items to be added to the list from the worker thread to the UI thread and add there so that you don't need to synchronize the access to the list?
            • Have you ever used QCoreApplication::processEvents() in a loop so that the UI remains responsive?

            I can go on and on with much more questions because this description is not enough:

            "The worker thread will be writing values to a list for several seconds. Meanwhile, I would need to read and remove values from the list from the GUI thread while the working thread is still running."

            1 Reply Last reply
            0
            • Chris KawaC Offline
              Chris KawaC Offline
              Chris Kawa
              Lifetime Qt Champion
              wrote on last edited by
              #6

              I might be over-simplifying but from the description it sounds all you need is a thread-safe list.
              Should be pretty easy to either make one yourself or just create an access wrapper for the QList i.e. a class that would hold a pointer to the list and have mutex guarded access methods like append(), remove(), at() etc.

              1 Reply Last reply
              0
              • S Offline
                S Offline
                Sigsegv
                wrote on last edited by
                #7

                Here is a minimal simplification of what I want to accomplish:

                In this example, I use public calls for removing and reading values. Obviously, these calls are not thread-safe, but I need them in order to read the values from the list inmediately when the user demands them. The goal would be finding a thread-safe way to do the same.

                main.cpp:
                @#include "mainwindow.h"
                #include <QApplication>

                int main(int argc, char *argv[])
                {
                QApplication a(argc, argv);
                MainWindow w;
                w.show();
                return a.exec();
                }@

                mainwindow.h:
                @#ifndef MAINWINDOW_H
                #define MAINWINDOW_H

                #include "ui_mainwindow.h"
                #include <QMainWindow>
                #include <QObject>
                #include <QThread>
                #include <QKeyEvent>

                class Worker : public QObject
                {
                Q_OBJECT

                public:
                QString read(int index)
                {
                return (index >= 0 && index < stringList.size()) ? stringList.at(index) : QString();
                }
                void remove(int index)
                {
                stringList.removeAt(index);
                }

                public slots:
                void Load()
                {
                for(unsigned int i=0; i<999999999; i++)
                stringList << QString::number(i);
                }

                private:
                QStringList stringList;
                };

                namespace Ui { class MainWindow; }

                class MainWindow : public QMainWindow
                {
                Q_OBJECT

                public:
                explicit MainWindow(QWidget *parent = 0) : QMainWindow(parent), ui(new Ui::MainWindow)
                {
                ui->setupUi(this);

                    worker = new Worker;
                    worker->moveToThread(&workerThread);
                    connect(&workerThread, SIGNAL(finished()), worker, SLOT(deleteLater()));
                    connect(this, SIGNAL(Load()), worker, SLOT(Load()));
                    workerThread.start();
                
                    emit Load();
                }
                ~MainWindow()
                {
                    delete ui;
                    workerThread.quit();
                    workerThread.wait();
                    delete worker;
                }
                

                signals:
                void Load();

                private:
                Ui::MainWindow *ui;
                Worker *worker;
                QThread workerThread;

                private slots:
                void on_spinBox_valueChanged(int newValue)
                {
                ui->label->setText(worker->read(newValue));
                }

                protected:
                void keyPressEvent(QKeyEvent *event)
                {
                if(event->key() == Qt::Key_Delete)
                {
                worker->remove(ui->spinBox->value());
                ui->label->setText(QString());
                }
                }
                };

                #endif // MAINWINDOW_H@

                1 Reply Last reply
                0
                • C Offline
                  C Offline
                  ckakman
                  wrote on last edited by
                  #8

                  Hi,

                  I can make a couple of suggestions:

                  • Keep the list in mainwindow. Send items from worker to mainwindow via a signal. It is thread-safe. UI thread not blocked. But lots of async calls.
                  • Keep the list in mainwindow. Store a certain number of items in a list or preferably vector. Send the vector to mainwindow via a signal. Resume storing items in an empty vector, etc. Fewer async calls.
                  • Don't create a worker thread. Start adding items to a list or vector, but call qApp->processEvents() after every N items. You should determine a reasonable N so that the UI remains responsive. No async calls, but blocks UI thread for small durations which may not be noticable by the user if N is chosen properly.
                  1 Reply Last reply
                  0
                  • Chris KawaC Offline
                    Chris KawaC Offline
                    Chris Kawa
                    Lifetime Qt Champion
                    wrote on last edited by
                    #9

                    So exactly what I suggested. Just wrap the list << operator in a method of Worker class and then guard that and the read() and remove() with a mutex member variable.

                    1 Reply Last reply
                    0
                    • S Offline
                      S Offline
                      Sigsegv
                      wrote on last edited by
                      #10

                      [quote author="Chris Kawa" date="1420317000"]So exactly what I suggested. Just wrap the list << operator in a method of Worker class and then guard that and the read() and remove() with a mutex member variable.[/quote]

                      I understand mutexes as mechanisms that ensures access serialization between threads within a particular section of code, so that section of code is executed by one thread at a time. Since, in my example, readings and writings are executed from different methods (both executed by different threads), I fail to see how the use mutexes can grant thread-safety to my list operations. Assuming you mean something like this:

                      @read()
                      {
                      mutex.lock();
                      //read from the list
                      mutex.unlock();
                      }@
                      @write()
                      {
                      mutex.lock();
                      //write on the list
                      mutex.unlock();
                      }@
                      @remove()
                      {
                      mutex.lock();
                      //remove an item from the list
                      mutex.unlock();
                      }@

                      Only one thread can execute read(), write() or remove() at the same time, but up to 3 threads may access the list simultaneously (if the threads call different methods).

                      1 Reply Last reply
                      0
                      • Chris KawaC Offline
                        Chris KawaC Offline
                        Chris Kawa
                        Lifetime Qt Champion
                        wrote on last edited by
                        #11

                        bq. Assuming you mean something like this

                        I would suggest QMutexLocker, but in principle yes, that's it.

                        bq. Only one thread can execute read(), write() or remove() at the same time, but up to 3 threads may access the list simultaneously

                        I don't understand. What do you mean by "access"? read(), write() and remove() are the access and the mutex ensures that only one at a time happens, so after each of these operations the list is in a coherent state. Do you want to "access" the list in some other way than through these methods?

                        1 Reply Last reply
                        0
                        • JKSHJ Offline
                          JKSHJ Offline
                          JKSH
                          Moderators
                          wrote on last edited by
                          #12

                          Hi,
                          [quote author="Sigsegv" date="1420334628"]I understand mutexes as mechanisms that ensures access serialization between threads within a particular section of code, so that section of code is executed by one thread at a time. Since, in my example, readings and writings are executed from different methods (both executed by different threads), I fail to see how the use mutexes can grant thread-safety to my list operations. Assuming you mean something like this:

                          @read()
                          {
                          mutex.lock();
                          //read from the list
                          mutex.unlock();
                          }@
                          @write()
                          {
                          mutex.lock();
                          //write on the list
                          mutex.unlock();
                          }@
                          @remove()
                          {
                          mutex.lock();
                          //remove an item from the list
                          mutex.unlock();
                          }@

                          Only one thread can execute read(), write() or remove() at the same time, but up to 3 threads may access the list simultaneously (if the threads call different methods).[/quote]You have misunderstood how mutexes work.

                          Suppose two different functions (read() and write() ) lock the same mutex object.

                          Scenario 1: Thread X calls read() first, then Thread Y calls write() before X has finished reading. Y will be blocked until X unlocks the mutex -- The write() function will wait for the read() function to finish before proceeding.

                          Scenario 2: Thread Y calls write() first, then Thread X calls read() before Y has finished writing. X will be blocked until Y unlocks the mutex -- The read() function will wait for the write() function to finish before proceeding.

                          You might find the "Synchronizing Threads":http://doc.qt.io/qt-5/threads-synchronizing.html article helpful.

                          Qt Doc Search for browsers: forum.qt.io/topic/35616/web-browser-extension-for-improved-doc-searches

                          1 Reply Last reply
                          0
                          • S Offline
                            S Offline
                            Sigsegv
                            wrote on last edited by
                            #13

                            [quote author="JKSH" date="1420364578"]Hi,
                            You have misunderstood how mutexes work.

                            Suppose two different functions (read() and write() ) lock the same mutex object.

                            Scenario 1: Thread X calls read() first, then Thread Y calls write() before X has finished reading. Y will be blocked until X unlocks the mutex -- The write() function will wait for the read() function to finish before proceeding.

                            Scenario 2: Thread Y calls write() first, then Thread X calls read() before Y has finished writing. X will be blocked until Y unlocks the mutex -- The read() function will wait for the write() function to finish before proceeding.

                            You might find the "Synchronizing Threads":http://doc.qt.io/qt-5/threads-synchronizing.html article helpful.[/quote]

                            You're right, I misunderstood how mutexes work.
                            I'll consider the use of public functions wrapped in mutexes as the optimal solution for my problem and mark this thread as solved.

                            Thank you all for your replies and patience ;)

                            1 Reply Last reply
                            0
                            • JKSHJ Offline
                              JKSHJ Offline
                              JKSH
                              Moderators
                              wrote on last edited by
                              #14

                              You're most welcome. :) Happy coding!

                              Qt Doc Search for browsers: forum.qt.io/topic/35616/web-browser-extension-for-improved-doc-searches

                              1 Reply Last reply
                              0

                              • Login

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