multithreadingqtqthreadqtconcurrentqmutex

Using QMutexLocker to Protect Shared Variables when Running Function with QtConcurrent


I do a discovery process in a background thread by using QtConcurrent:

// Start the discover process in the background thread so it doesn't block the gui
*m_Future = QtConcurrent::run(this, &Controller::StartDiscover);
m_Watcher->setFuture(*m_Future);

I previously had not put a Mutex to protect the shared variables inside that function that could be accessed while the background thread was being run. This was causing somewhat random lockups during my 'scanning' operation.

I've now implemented mutex locks be creating a QMutexLocker at the beginning of that function.

int Controller::StartDiscover() {

    // Lock mutex
    QMutexLocker ml(&m_Mutex);

    // Zero
    m_NumberBoundDevices = 0;

    // Update to scanning
    m_Status = Scanning;

    // Discover slaves
    int numberAttachedSlaves = m_Client->DiscoverSlaves();
    m_Client->setTimeout(20000); // 20 Second Timeout

    if ( numberAttachedSlaves > 0 ) {

        int cnt = 0;
        while ( cnt < 3 ) {

                for (int slave = 1 ; slave <= numberAttachedSlaves ; slave++ ) {

                    // Get information about this slave
                    QDBusPendingReply<uchar> reply = m_Client->SlaveService(slave,m_Packet);
                    reply.waitForFinished(); // Wait for it to complete
                    if (!reply.isValid()) {
                        m_Client->SlaveService(slave,m_Packet);
                        reply.waitForFinished();
                    }
                    if ( reply.isError() ) {
                        QString errorMsg = reply.reply().errorMessage();
                    }

                }

                // Increment counter
                cnt++;
        }

    }

    // Update
    m_NumberBoundDevices = numberAttachedSlaves;

    // Return the number of devices discovered
    return numberAttachedSlaves;

}

Will this protect all shared variables within the function? Or, should I explicitly use QMutex.lock() and unlock() around each m_* variable?

Thanks


Solution

  • Consider this: -

    char buffer[]
    void ReadFromBuffer()
    {
        QMutexLocker ml(&m_Mutex);
        // read contents of buffer
    }
    
    void WriteToBuffer()
    {
        QMutexLocker ml(&m_Mutex);
        // write to buffer
    }
    

    If ReadFromBuffer is running in a separate thread to WriteToBuffer, you want to ensure that read and write don't occur at the same time.

    If one thread is executing in WriteToBuffer and locks the mutex, when the other thread enters ReadFromBuffer and executes its mutex locker, it checks to see if the mutex is locked. If it is locked, the thread pauses and waits for it to be unlocked. This occurs when the QMutexLocker object goes out of scope in the first function that locked the mutex.

    That's why QMutexLocker is required around all code accessing shared objects.