一、澄清概念
什么是信号量?
信号量的使用主要是用来保护共享资源,使得资源在一个时刻只有一个线程所拥有。是线程同步的重要手段之一,保证线程安全。
与互斥锁有何区别?
信号量不一定是锁定某一个资源,而是流程上的概念,比如:有A,B两个线程,B线程要等A线程完成某一任务以后再进行自己下面的步骤。
而线程互斥锁则是“锁住某一资源”的概念,在锁定期间内,其他线程无法对被保护的数据进行操作。在有些情况下两者可以互换。
Qt中的信号量长啥样?
Qt帮助中给出答案:
官方解释及示例:
二、实战演练
问题:实现生产者-消费者模型
解决:两个QSemaphore管理两个线程Producer(生产者),Consumer(消费者)
示例代码如下:
<span style="font-family:Verdana, Geneva, Arial, Helvetica, sans-serif;">#include <QtCore>
#include <stdio.h>
#include <stdlib.h>
const int DataSize = 100000;
const int BufferSize = 8192;
char buffer[BufferSize];
QSemaphore freeBytes(BufferSize);//生产者初始拥有4096B数据缓存区
QSemaphore usedBytes(0);//消费者初始使用了0字节数据
class Producer : public QThread//生产者
{
public:
void run();
};
void Producer::run()
{
qsrand(QTime(0,0,0).secsTo(QTime::currentTime()));
for (int i = 0; i < DataSize; ++i) {
freeBytes.acquire();
buffer[i % BufferSize] = "ACGT"[(int)qrand() % 4];
usedBytes.release();
}//若buffer充满了消费者未读的数据,acquire()就会被阻塞,直到消费者开始消费这些数据
}
class Consumer : public QThread//消费者
{
public:
void run();
};
void Consumer::run()
{
for (int i = 0; i < DataSize; ++i) {
usedBytes.acquire();
fprintf(stderr, "%c", buffer[i % BufferSize]);
freeBytes.release();
}//若buffer没有任何可读数据,acquire()就会被阻塞,直到生产者生产一些数据
fprintf(stderr, "\n");
}
int main(int argc, char *argv[])
{
QCoreApplication app(argc, argv);
Producer producer;
Consumer consumer;
producer.start();
consumer.start();
producer.wait();
consumer.wait();
return 0;
}</span>
生产者线程和消费者线程启动后,生产者把自由空间(freeBytes)转变成用过的空间(usedBytes),消费者再把用过的空间中的数据消费掉转变成自由空间,如此往复,便是经典的生产者-消费者模型。