?
Solved

QWaitCondition

Posted on 2011-04-29
4
Medium Priority
?
736 Views
Last Modified: 2013-11-23
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

0
Comment
Question by:rkreddy_kbs
  • 2
3 Comments
 

Author Comment

by:rkreddy_kbs
ID: 35492769

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
 

Author Comment

by:rkreddy_kbs
ID: 35493757
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
 
LVL 12

Accepted Solution

by:
HappyCactus earned 1000 total points
ID: 35511945
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

Featured Post

Free Tool: IP Lookup

Get more info about an IP address or domain name, such as organization, abuse contacts and geolocation.

One of a set of tools we are providing to everyone as a way of saying thank you for being a part of the community.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

In our object-oriented world the class is a minimal unit, a brick for constructing our applications. It is an abstraction and we know well how to use it. In well-designed software we are not usually interested in knowing how objects look in memory. …
How to install Selenium IDE and loops for quick automated testing. Get Selenium IDE from http://seleniumhq.org Go to that link and select download selenium in the right hand column That will then direct you to their download page. From that p…
THe viewer will learn how to use NetBeans IDE 8.0 for Windows to perform CRUD operations on a MySql database.
The viewer will learn how to use and create keystrokes in Netbeans IDE 8.0 for Windows.
Suggested Courses

829 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question