信号量可以获取多次,可以用来保护一定数量的同种资源,信号量的典型用例是控制生产者和消费者之间共享的环形缓冲区
生产者,消费者实例中对同步的需求有两处:
1.生产者快于消费者,将会覆盖消费者还没有读取的数据;
2.生产者慢于消费者,将会读取到一些过期的数据;
两种解决方案:
1.首先使生产者填满缓冲区,然后等待消费者读取整个缓冲区;
2.使生产者和消费者线程同时分别操作缓冲区的不同部分;
#include <QCoreApplication> #include<QSemaphore> #include<QThread> #include<stdio.h> const int DataSize=1000; const int BufferSize=80; int buffer[BufferSize]; QSemaphore freeBytes(BufferSize); //生产者信号量,目前空闲的单元数为80 QSemaphore usedBytes(0); //消费者信号量,目前可用的单元数为0 class Producer:public QThread { public: Producer(); void run(); }; Producer::Producer() { } void Producer::run() { for(int i=0;i<DataSize;i++) { freeBytes.acquire();//生产者首先获得一个空闲单元,若此时缓冲区被消费者尚未读取的数据填满,对此函数的调用就会阻塞 buffer[i%BufferSize]=(i%BufferSize); //buffer的最大量80 usedBytes.release();//表示这个单元被填写,消费者可以使用 } } class Consumer:public QThread { public: Consumer(); void run(); }; Consumer::Consumer() { } void Consumer::run() { for(int i=0;i<DataSize;i++) { usedBytes.acquire(); //消费和线程首先获取一个可被读取的单元,若缓冲区没有包含任何可以读取的数据,对此函数的调用阻塞 fprintf(stderr,"%d",buffer[i%BufferSize]);//stderr标准错误流 if(i%16==0&&i!=0) { fprintf(stderr,"\n"); //每16个数据进行一次换行打印 } freeBytes.release(); //单元变成空闲,生产者可用 } fprintf(stderr,"\n"); } int main(int argc, char *argv[]) { QCoreApplication a(argc, argv); Producer producer; //生产者线程 Consumer consumer; //消费者线程 producer.start(); consumer.start(); producer.wait(); producer.wait(); return a.exec(); }
buffer作为缓冲区;
生产者和消费者线程同时工作,依次输出1000个数据;