信号量(Semaphore)有时被称为信号灯,是在多线程环境下使用的一种设施,可以用来保证两个或多个关键代码段不被并发调用。在进入一个关键代码段之前,线程必须获取一个信号量;一旦该关键代码段完成了,那么该线程必须释放信号量。其他想进入该关键代码段的线程必须等待,直到第一个线程释放信号量。为了完成这个过程,需要创建一个信号量VI,然后将Acquire Semaphore VI以及Release Semaphore VI分别放置在每个关键代码段的首末端。确认这些信号量VI引用的是初始创建的信号量。
QSemaphore 是QMutex的一般化,是特殊的线程锁,允许多个线程同时访问临界资源。信号量可以理解为对互斥量功能的扩展,互斥量只能锁定一次,而信号量可以获取多次,且可以用来保护一定数量的同种资源。acquire(n)用于获取 n 个资源,当没有足够的资源时,调用者将被阻塞直到有足够的可用资源。release(n)用于释放 n 个资源。
QSemaphore 类成员主要函数介绍如下。
● QSemaphore (int n = 0) :建立对象时可以给它 n 个资源,默认为0。
● void acquire (int n = 1) :获取1个资源。
● int available () const :返回在任意时刻可用的资源数目。
● void release (int n = 1) :释放1个资源。
● bool tryAcquire (int n = 1) :如果得不到足够的资源会立即返回。
● bool tryAcquire (int n, int timeout) :如果得不到足够的资源会等待timeout时间返回。
下面给出实现生产者消费者模型的代码。
#include <QtCore/QCoreApplication>
#include <QSemaphore>//信号量头文件
#include <QThread>
#include <cstdlib>
#include <cstdio>
const int DataSize = 100000; //数据大小
const int BufferSize = 8192; //缓存区大小
char buffer[BufferSize];
QSemaphore production(BufferSize);
QSemaphore consumption;
class Producer:public QThread
{
public:
void run();
};
void Producer::run()
{
for(int i = 0; i < DataSize; i++)
{
production.acquire();//获取信号量
buffer[i%BufferSize] = "ACGT"[(int)qrand()%4];//随机获取一个字母
consumption.release();//释放信号量
}
}
class Consumer:public QThread
{
public:
void run();
};
void Consumer::run()
{
for(int i = 0; i < DataSize; i++)
{
consumption.acquire();//获取信号量
fprintf(stderr, "%c", buffer[i%BufferSize]);
production.release();//释放信号量
}
fprintf(stderr, "%c", "\n");
}
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
Producer productor;
Consumer consumer;
producer.start();
consumer.start();
producer.wait();
consumer.wait();
return a.exec();
}