EA&UML日拱一卒-多任务编程超入门-(12)关于Semaphore,一个不得不说的实例

每 一个成熟的开发工具,都会附带很多示例,用来说明工具本身和相关语言的用法。编程者往往会忽略这些例子而直奔自己的开发目标。基本上这也不是什么大问题, 因为那些例子大多很简单,用的时候看一下就行了。但是Qt中关于Semaphore的实例,却是无论如何都不应该忽略的。


代码说明


全局变量


//数据量
const
int DataSize = 100000;
//缓冲区大小
const
int BufferSize = 8192;  
//缓冲区
char
buffer[BufferSize];      
//缓冲区空闲空间Semaphore
QSemaphore freeBytes(BufferSize);  
//缓冲区数据Semaphore
QSemaphore usedBytes;         


写数据线程


class Producer : public QThread
{
public
:
 
void run() override
 {
     
for (int i = 0; i < DataSize; ++i) {
         
freeBytes.acquire();
         
buffer[i % BufferSize]
               = "ACGT"[(int)qrand() % 4];
         
usedBytes.release();
     
}
 
}
};


首先略过两个Semaphore来读程序。run方法向缓冲区中写入数据。由于buffer的下标为i % BufferSize,所以这是一个循环队列。

接 下来看两个Semaphore的用法。freeBytes是空闲领域关联的Semaphore,只要循环队列中有空闲空间,acquire就会顺利通过, 否则写数据线程在acquire方法处发生阻塞。当数据写入成功以后,调用usedBytes的release方法,增加usedBytes的计数值。


读数据线程


class Consumer : public QThread
{
public
:
 
void run() override
 
{
     
for (int i = 0; i < DataSize; ++i) {
         
usedBytes.acquire();
         
fprintf(stderr, "%c",    
                  buffer[i % BufferSize]);
         
freeBytes.release();
     
}
 
}
};


run 方法从循环队列中读数据。关键还是两个Semaphore的用法。usedBytes是数据领域关联的Semaphore,只用循环队列中有数 据,acquire就会顺利通过,否则读数据线程在acquire方法处发生阻塞。当数据读出成功以后,调用freeBytes的release方法,增 加freeBytes的计数值。


主程序


int main(int argc, char *argv[])
{
 
Producer producer;
 
Consumer consumer;
 
producer.start();
 
consumer.start();
 
producer.wait();
 
consumer.wait();
 
return 0;
}


主程序很简单,分别启动两个线程,然后就安静地等待两个线程结束。


稍微总结一下


  1. 这个实例的核心就是一个循环队列和两个Samphore

  2. 通过循环队列传递数据

  3. 通过两个Semaphore同时实现了数据的保护和两个线程之间的同步


思考题


  1. 如何设计一个类,将核心的部分包装起来以便将来使用?

  2. 有可能让这个类被更多的线程同时使用么?


写在文章的最后


既然已经读到这里了,拜托大家再用一分钟时间,将文章转发到各位的朋友圈,微信群中。


本公共号的成长需要您的支持!
阅读更多更新文章,请扫描下面二维码,关注微信公众号【面向对象思考】
EA&UML日拱一卒-多任务编程超入门-(12)关于Semaphore,一个不得不说的实例