这个例子展示了在Qt中使用多线程,在并发程序中使用QSemaphore要比QMutex高级。
这个例子是生产者生成数据,消费者消费数据,QSemaphore等同于QWaitCondition + QMutex。
下面的这些代码中
const int DataSize = 100000;
const int BufferSize = 8192;
char buffer[BufferSize];
QSemaphore freeBytes(BufferSize);
QSemaphore usedBytes;
这里的DataSize是循环的总次数,freeBytes(BufferSize)是指目前freeBytes的阈值为8192,而usedBytes的阈值为0,这个阈值的作用将会在下面说明。
下面来看下生产者代码:
class Producer : public QThread
{
public:
void run() override
{
for (int i = 0; i < DataSize; ++i) {
freeBytes.acquire();
buffer[i % BufferSize] = "ACGT"[QRandomGenerator::global()->bounded(4)];
usedBytes.release();
}
}
};
从中可以看到生产者开了一个线程去操作,freeBytes.acquire()他的作用是需要获取一个数据,当调用了这个函数后其available()的返回值,也就是资源数量就会减少1,如果调用为freeBytes.acquire(5)那么将会减少5,但是如果不够减少,那么就不会减少,这个线程就和被挂起,等待freeBytes有数据后就会被激活。而这个usedBytes.release()会生成一个资源,也就是说usedBytes.available()其返回值会比以前加1,这里也可以填写参数usedBytes.release(5).
下面是消费者代码:
class Consumer : public QThread
{
Q_OBJECT
public:
void run() override
{
for (int i = 0; i < DataSize; ++i) {
usedBytes.acquire();
fprintf(stderr, "%c", buffer[i % BufferSize]);
freeBytes.release();
}
fprintf(stderr, "\n");
}
};
同样消费者也是一个线程,usedBytes的默认的阈值为0,usedBytes.acuire()如果为0就将其阻塞掉。同样freeBytes将会+1,这里是不会被阻塞的,能阻塞的地方只有usedBytes.acquire()。这里的阻塞用怎么的词汇应该是挂起。
下面是main函数:
int main(int argc, char *argv[])
{
QCoreApplication app(argc, argv);
Producer producer;
Consumer consumer;
producer.start();
consumer.start();
producer.wait();
consumer.wait();
return 0;
}
在main函数中有一个要注意的就是wait,使用这个可以进行等待,等生产者和消费线程完成后才会return 0;
最后生产者生产一个数据就会被使用,消费者被usedBytes信号量阻塞挂起了,生产者产生一个就和被消费。这里再给出一个程序截图: