這個例子展示了在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信號量阻塞掛起了,生產者產生一個就和被消費。這裏再給出一個程序截圖: