Search code examples
multithreadingqtqthread

Worker in QThread


I have a worker object in a QThread running some stuff in infinite loop. Somewhere I saw a code that in the worker there was for example 'checkStatus()' method returning some boolean value. This method is not slot but a public method. What I am interested in, wether is it safe to call this method from the main thread if this worker object is already moved into a QThread and is running its infinite loop? Shouldn't I use signals-slots instead?

I tried something like this in constructor of main window:

....
startDataInputSlot(); // starting thread and moving worker into thread

while(1) dataInputWorker->checkStoppedStatus(); // trying to access some variables in worker object

....

startDataInputSlot() started a thread and moved the worker into that thread. In infinite loop of worker it periodically checks the value which the next infinite cycle (in main window) tries to access. No QMutexes were used and a program worked properly without crashing. Is this safe to use?


Solution

  • It is not safe to have a direct access to worker members without mutexes. This is an example of how it can be implemented:

    class Worker : public QObject
    {
    public slots:
        void doHeavyJob()
    
    public:
        bool getStatus();
    
    private:
        int data;
        QMutex mutex;
    }
    

    doHeavyJob is the main worker function which modifies the data variable. It should be launched via signal-slot mechanism, as in this case it will be running in the the worker thread:

    void Worker::doHeavyJob()
    {
        while (true)
        {
             mutex.lock();
    
             // do something with the data
             data++;
    
             mutex.unlock();
        }
    }
    
    QThread *thread = new QThread;
    Worker *worker = new Worker;
    worker->moveToThread(thread);
    
    connect(thread, SIGNAL(started()), worker, SLOT(doHeavyJob()));
    
    thread->start();
    

    And here you can check the worker status directly from another (main) thread:

    bool Worker::getStatus()
    {
        bool isGood;
    
        mutex.lock();
        isGood = data > 10;
        mutex.unlock();
    
        return isGood;
    }
    

    Inside getStatus you should lock the data variable because it can be changed inside doHeavyJob slot which is running in the worker thread.

    Also you can't launch getStatus function as a slot because it will be only executed when the control returns to the worker thread event loop, but if you have 'infinite' doHeavyJob function, it will never happen.