• 8063阅读
  • 4回复

[提问]对于qwaitcondition的理解 [复制链接]

上一主题 下一主题
离线javiy
 
只看楼主 倒序阅读 楼主  发表于: 2013-04-07
前两天在网上看到一篇文章,关于书上那个典型的生产者消费者的问题。我对qwaitcondition的理解一直没有搞清楚,故上来求助。首先是代码。
/*
使用QWaitCondition和QMutex可以实现比信号量更精确的控制
*/


#include <QtCore>
#include <iostream>


//const int DataSize = 100000;
//const int BufferSize = 4096;




const int DataSize = 100;
const int BufferSize = 100;
char buffer[BufferSize];


//与信号量不同的程序
QWaitCondition bufferIsNotFull; //QWaitCondition允许在一定条件下触发其它多个线程
QWaitCondition bufferIsNotEmpty;
QMutex mutex;
int usedSpace = 0;//不是信号量,而是用来代表在缓冲器中存在多少个“用过的”字节


//生产者
class Producer : public QThread
{
public:
    void run();
};


void Producer::run()
{
    for (int i = 0; i < DataSize; ++i) {
        mutex.lock();//锁定:保护对usedSpace变量的访问
        //如果缓冲区都是用过的字节,那么就等待
        while (usedSpace == BufferSize)
            bufferIsNotFull.wait(&mutex);//wait的过程:解锁->阻塞当前线程->满足条件->锁定->返回
        buffer[i % BufferSize] = "ACGT"[uint(rand()) % 4];
        std::cerr<<"P";//代表一次生产者线程的运行
        ++usedSpace;
        bufferIsNotEmpty.wakeAll();//Wakes all threads waiting on the wait condition.
        mutex.unlock();//解锁
    }
}


//消费者
class Consumer : public QThread
{
public:
    void run();
};


void Consumer::run()
{
    for (int i = 0; i < DataSize; ++i) {
        mutex.lock();//
        //如果缓冲区里“用过的”字节数目为0,则等待
        while (usedSpace == 0)
            bufferIsNotEmpty.wait(&mutex);
        //std::cerr << buffer[i % BufferSize];
        char Cons = buffer[i % BufferSize];
        std::cerr<<"c";
        --usedSpace;
        bufferIsNotFull.wakeAll();
        mutex.unlock();
    }
    std::cerr << std::endl;
}


int main()
{
    Producer producer;
    Consumer consumer;
    producer.start();
    consumer.start();
    producer.wait();
    consumer.wait();
    return 0;
}


执行结果
(1)

const int DataSize = 100;
const int BufferSize = 1;
PcPcPcPcPcPcPcPcPcPcPcPcPcPcPcPcPcPcPcPcPcPcPcPcPcPcPcPcPcPcPcPcPcPcPcPcPcPcPcPcPcPcPcPcPcPcPc
(2)

const int DataSize = 100;
const int BufferSize = 10;
结果1

PPPPPPPPPPcPcPcPcPcPcPcPcPcPcPcPcPcPcPcPcPcPcPcPcPcPcPcPcPcPcPcPcPcPcPcPcPcPcPcPcPcPcPcPcPcPcPcPcPcPcPcPcPcPcPcPcPcPcPcPcPcPcPcPcPcPcPcPcPcPcPcPcPcPcPcPcPcPcPcPcPcPcPcPcPcPcPcPcPcPcPcPcPcPcPcccccccccc

结果2
PPPPPPPPPPcPcPcPcPcPcPcPcPccccccccccPPPPPPPPPPccccccccccPPPPPPPPPPccccccccccPPPPPPPPPPccccccccccPPPPPPPPPPccccccccccPPPPPPPPPPccccccccccPPPPPPPPPPccccccccccPPPPPPPPPPccccccccccPPPPPPPPPPccccccccccPPcc

结果3
PPPPPPPPPPccccccccccPPPPPPPPPPccccccccccPPPPPPPPPPccccccccccPPPPPPPPPPccccccccccPPPPPPPPP
重点是这个地方当 DataSize是100,BufferSize 是10 的时候为什么可能会有多种不同结果的输出呢。按照我的理解,生产者线程每次运行都先检测缓冲区是否写满,如果不满(假设一开始缓冲区就是空的),向缓冲区写入一个字节随机的数据,然后usedspace加一,之后的bufferIsNotEmpty.wakeAll()所唤醒的线程应该是消费者线程吧?如果不是,那这句话所唤醒的线程又是指哪一个?按照我的理解,生产者只要一产生数据就马上唤醒消费者去读取了,消费者读取之后,usedspace自减1,那还会有可能满足
while (usedSpace == BufferSize)  
bufferIsNotFull.wait(&mutex);
这样一个条件吗?我的理解是不是存在什么误区呢?
附上原文章地址:http://blog.csdn.net/xufenghfut/article/details/7857364



离线javiy
只看该作者 1楼 发表于: 2013-04-07
没有人可以帮一下吗?这个问题困扰了我好几天了
离线realfan

只看该作者 2楼 发表于: 2013-04-08
两个线程除了在缓冲区满和缓冲区空这两种状态外,其余情况可以看做是独立的.
生产线程只要是缓冲区未满,就会一直生产数据;
消费线程只要是缓冲区有数据,就会消费.
生产数据的速度和消费数据的速度是不确定的,取决于线程调度.所以,连续几个P几个c都是不确定的.
离线realfan

只看该作者 3楼 发表于: 2013-04-08
while (usedSpace == BufferSize)  
bufferIsNotFull.wait(&mutex);
既然两个线程是独立运行,就有可能缓冲区满了,消费还没有进行,或者已经消费尽了,生产还未进行.因为两个线程被调度的时间片有一定随机性.
离线realfan

只看该作者 4楼 发表于: 2013-04-08
生产线程启动后,只管生产,它是不知道什么时候消费线程来取数据的.它只要保证缓冲区满了后,等待缓冲区有空位,再生产.bufferIsNotFull.wait来控制
消费线程启动后,只管消费,它也不知道什么时候生产线程生成数据.它只保证缓冲区为空时,等待生产线程产生数据.bufferIsNotEmpty.wait控制

不知道这样说,能否理解.
快速回复
限100 字节
 
上一个 下一个