QThread state when at start() call thread is still running, but after is already not

1k views Asked by At

I have a GUI thread where I call write(QString text) method of another MyQThread.
MyQthread contains QMutex mutex and QList<QString> list. Here is the write() and run() methods of MyQThread:

void MyQThread::write(QString text)
{
     mutex.lock();
     list.append(text); //Point C
     mutex.unlock();
     start(); //Point D
}  

void MyQThread::run()
{
     mutex.lock();

     while(!list.isEmpty())
     {
         QString text = list.takeFirst();
         mutex.unlock();
         ...//do something
         mutex.lock(); //Point A
     }

     mutex.unlock(); //Point B
}  

For example we are at the 'point A'. After this point we are checking the list and it is empty, so we are going to 'point B'. At this moment write() is called, mutex is still locked, so GUI thread is waiting before 'point C'.
Now we are at the 'point B', after this GUI thread is unlocked and start() ('Point D') is called.
Is it possible, that at 'point D' MyQThread is still running?
In this case calling of start() do nothing. And newly added item in the list will not be processed in run() until next call of the write().
Additional information. In my case here is only one instance of MyQThread.

3

There are 3 answers

2
Funt On BEST ANSWER

@alexisdm thanks for the idea. What about this solution:

class MyQThread:
    public: QThread
{
    ...
    QList<QString> list;
    QMutex mutex;
    QWaitCondition listNotEmpty;
}

void MyQThread::write(QString text)
{
     QMutexLocker locker(&mutex);
     list.append(text);
     listNotEmpty.wakeAll();
}  

void MyQThread::run()
{
     forever
     {
         mutex.lock();
         if(list.isEmpty())
             listNotEmpty.wait(&mutex);

         if(list.isEmpty())
         {
             mutex.unlock();
             continue;
         }
         QString text = list.takeFirst();
         mutex.unlock();
         ...//do something
     }
}  

And what about the second parameter of wait() - unsigned long time = ULONG_MAX.
It seems that in my case it will not be error, when write() method is not called for a long time and wait() will return false in run() after ULONG_MAX. And in this case I need just to wait again...

And in documentation is written:

The mutex will be returned to the same locked state.

Does it mean, that mutex will be always locked after wait() even if mutex was not locked before wait() or wait() returns false?

3
Greenflow On

QThread has the methods 'isRunning' and 'isFinished'. So you could query the thread state. And sure, your thread could still be running at 'Point D'.

But you really should stop here and do some reading. https://www.qt.io/blog/2010/06/17/youre-doing-it-wrong and http://woboq.com/blog/qthread-you-were-not-doing-so-wrong.html

And most certainly the Qt docs about the QMutexLocker.

5
Phlucious On

Yes. Although the probability of having a race condition is low, I believe there's still a chance that QThread will still be sending signals and such. Use QThread::wait before you call start() to be sure.

Edit: Agreed on the need to consider QMutexLocker. That code's going to get scary complicated pretty fast and you can't be sure that you'll remember to unlock with every exit point.

Edit2: Perhaps a QReadWriteLock might be more interesting in your case?