QWaitCondition

Hello
I want to implement 2 threads (Producer/Consumer) in Qt 4.6.2  that interact with each other using QWaitCondition (i.e., wait/notify meaning T1 does something, notifies T2 and goes to wait again . The thread T2 who until now was waiting, when notified by T1, wakes up, does something and then notifies T1 and so on..)

Is QWaitCondition the right choice or is there something else.. I implemented the code but it gets into some deadlock. Here is my code :-

class DemoApp : public QMainWindow {
    Q_OBJECT
public:
    DemoApp(QWidget *parent = 0);
    ~DemoApp();

    QMutex wmutex, rmutex;

    QWaitCondition permitToWrite;
    QWaitCondition permitToRead;

private:    
    WriterThread *wthread; // this is our writer thread
    ReaderThread *rthread; // this is our reader thread
}

void DemoApp::on_StartButton_clicked()
{
    wthread = new WriterThread(this);
    wthread->start(); 

    rthread = new ReaderThread(this);
    rthread->start(); 

    permitToWrite.wakeAll();
}

//Writer Thread
WriterThread::WriterThread(QObject *parent)
    : QThread(parent)
{

    myParent = (DemoApp*)parent;
}

void WriterThread::run()
{
    while(1){
        {
	  myParent->wmutex.lock();
          myParent->permitToWrite.wait(&myParent->wmutex);
 	  writeSomething();
	  myParent->wmutex.unlock();
	  myParent->permitToRead.wakeAll();
	}
}

//Reader Thread
ReaderThread::ReaderThread(QObject *parent)
    : QThread(parent)
{

    myParent = (DemoApp*)parent;
}

void ReaderThread::run()
{
    while(1){
        {
	  myParent->rmutex.lock();
          myParent->permitToRead.wait(&myParent->rmutex);
 	  readSomething();
	  myParent->rmutex.unlock();
	  myParent->permitToWrite.wakeAll();
	}
}

Open in new window

rkreddy_kbsAsked:
Who is Participating?
 
HappyCactusConnect With a Mentor Commented:
Use a semaphore: writer use release() to permit one reading to the reader. Reader use acquire() to wait until there is something to read.
This is a sample code.
Remember to protect your resource pool with a mutex. I suppose in my example that m_queue is a pointer to the common QList<MyMessage>. m_semaphore is a pointer to the common QSemaphore and m_mutex to the common QMutex. In a production quality code, all this should be embedded in a MyQueue Class Object.
void WriterThread::run()
{
    while(1){
        {
           m_mutex->lock();
           m_queue->push_back (message);
           m_semaphore->release();
           m_mutex->unlock();
	}
}

void ReaderThread::run()
{
    while(1){
        {
          m_semaphore->acquire();    // here waits
          m_mutex->lock();
          mymessage = m_queue->front();
          m_queue->pop_front();
          m_mutex->unlock();
	}
}

Open in new window

0
 
rkreddy_kbsAuthor Commented:

For most of the iterations, they work correctly as follows :-

The W (writer) writesSomething, unlocks wmutex, wakes Reader, locks wmutex and then waits on permitToWrite.
The reader R is scheduled and it does its sequence as readSomething, unlock rmutex, wakes Writer, lock rmutex and then waits on permitToRead

the above steps repeat but after some time, the sequence gets disturbed as follows :-

The W (writer) writesSomething, unlocks wmutex, wakes Reader.
Now the reader is scheduled
The reader does its sequence as readSomething, unlock rmutex, wakes Writer, lock rmutex and then waits on permitToRead. Note here that the writer has been woken up but it was never waiting.
Now the writer is scheduled and it continues from where it left i.e. unlock wmutex and then waits on permitToWrite and it waits indefinitely here.

So now both reader and writer are waiting indefinitely for their respective permits.

Should I be using the same mutex instead of two mutexes. I tried but it did not work either.. pls advise.
0
 
rkreddy_kbsAuthor Commented:
I made the following changes and it seems to be working :-

Firstly use only mutex instead of wmutex and rmutex

void WriterThread::run()
{
    while(1){
        {
	  myParent->mutex.tryLock();
          myParent->permitToWrite.wait(&myParent->mutex);
 	  writeSomething();
	  myParent->permitToRead.wakeAll();
	}
}

void ReaderThread::run()
{
    while(1){
        {
	  myParent->mutex.tryLock();
          myParent->permitToRead.wait(&myParent->mutex);
 	  readSomething();
	  myParent->permitToWrite.wakeAll();
	}
} 

Open in new window

0
Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.

All Courses

From novice to tech pro — start learning today.