Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt
  • 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
Qt 6.11 is out! See what's new in the release blog

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

Scheduled Pinned Locked Moved General and Desktop
14 Posts 5 Posters 11.1k 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.
  • 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
    • ? Offline
      ? Offline
      A Former User
      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
          • ? Offline
            ? Offline
            A Former User
            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
                • ? Offline
                  ? Offline
                  A Former User
                  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
                      • ? Offline
                        ? Offline
                        A Former User
                        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
                          • Unsolved