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;
}
主程序很简单,分别启动两个线程,然后就安静地等待两个线程结束。
稍微总结一下
-
这个实例的核心就是一个循环队列和两个Samphore
-
通过循环队列传递数据
-
通过两个Semaphore同时实现了数据的保护和两个线程之间的同步
思考题
-
如何设计一个类,将核心的部分包装起来以便将来使用?
-
有可能让这个类被更多的线程同时使用么?
写在文章的最后
既然已经读到这里了,拜托大家再用一分钟时间,将文章转发到各位的朋友圈,微信群中。
本公共号的成长需要您的支持!
阅读更多更新文章,请扫描下面二维码,关注微信公众号【面向对象思考】