在qt用QSemaphore写一个多线程加入图片
时间: 2024-02-13 10:07:27 浏览: 86
QT中多线程
下面是一个使用 `QSemaphore` 实现多线程加载图片的示例:
```cpp
#include <QApplication>
#include <QWidget>
#include <QVBoxLayout>
#include <QHBoxLayout>
#include <QLabel>
#include <QImage>
#include <QPixmap>
#include <QFile>
#include <QSemaphore>
#include <QThread>
#include <QDebug>
const int kNumThreads = 4; // 线程数量
const int kMaxImages = 8; // 最大图片数量
class ImageLoader : public QObject
{
Q_OBJECT
public:
ImageLoader(QSemaphore *semaphore, const QString &filename, QLabel *label, QObject *parent = nullptr)
: QObject(parent), semaphore_(semaphore), filename_(filename), label_(label) {}
signals:
void finished();
public slots:
void load()
{
QFile file(filename_);
if (file.open(QIODevice::ReadOnly)) {
QImage image;
if (image.load(&file)) {
QPixmap pixmap = QPixmap::fromImage(image);
emit imageLoaded(pixmap);
}
}
file.close();
emit finished();
semaphore_->release();
}
void setImage(const QPixmap &pixmap)
{
label_->setPixmap(pixmap);
}
private:
QSemaphore *semaphore_;
QString filename_;
QLabel *label_;
};
class ImageLoaderThread : public QThread
{
Q_OBJECT
public:
ImageLoaderThread(QSemaphore *semaphore, const QString &filename, QLabel *label, QObject *parent = nullptr)
: QThread(parent), semaphore_(semaphore), filename_(filename), label_(label) {}
signals:
void imageLoaded(const QPixmap &pixmap);
protected:
void run() override
{
ImageLoader loader(semaphore_, filename_, label_);
connect(&loader, &ImageLoader::imageLoaded, this, &ImageLoaderThread::imageLoaded);
connect(&loader, &ImageLoader::finished, this, &ImageLoaderThread::quit);
loader.load();
}
private:
QSemaphore *semaphore_;
QString filename_;
QLabel *label_;
};
class MainWindow : public QWidget
{
public:
MainWindow(QWidget *parent = nullptr) : QWidget(parent)
{
QHBoxLayout *layout = new QHBoxLayout(this);
for (int i = 0; i < kMaxImages; ++i) {
QLabel *label = new QLabel(this);
label->setFixedSize(200, 200);
layout->addWidget(label);
labels_.append(label);
}
QThread::currentThread()->setObjectName("Main");
}
~MainWindow()
{
for (auto thread : threads_) {
thread->quit();
thread->wait();
delete thread;
}
}
void startLoading()
{
// 初始化信号量
semaphore_.release(kMaxImages);
// 启动线程
for (int i = 0; i < kNumThreads; ++i) {
ImageLoaderThread *thread = new ImageLoaderThread(&semaphore_, QString(":/images/%1.png").arg(i + 1), labels_.at(i));
threads_.append(thread);
connect(thread, &ImageLoaderThread::imageLoaded, this, &MainWindow::onImageLoaded, Qt::QueuedConnection);
thread->start();
}
}
public slots:
void onImageLoaded(const QPixmap &pixmap)
{
// 查找空闲的标签
int index = -1;
for (int i = 0; i < kMaxImages; ++i) {
if (labels_.at(i)->pixmap() == nullptr) {
index = i;
break;
}
}
// 设置图片
if (index >= 0 && index < kMaxImages) {
labels_.at(index)->setPixmap(pixmap);
}
}
private:
QList<QLabel *> labels_;
QList<ImageLoaderThread *> threads_;
QSemaphore semaphore_;
};
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
MainWindow window;
window.show();
window.startLoading();
return app.exec();
}
#include "main.moc"
```
在这个例子中,我们创建了一个 `ImageLoader` 类,负责从文件中加载图片,并将加载完成的图片转换成 `QPixmap` 类型,然后通过信号将图片传递给线程。`ImageLoaderThread` 类继承自 `QThread`,负责在子线程中创建 `ImageLoader` 对象,并连接信号槽,将加载完成的图片发送给主线程。主线程中创建了多个 `ImageLoaderThread` 对象,并启动线程,等待图片加载完成后将图片显示在 QLabel 控件中。为了控制最大并发数,我们使用了一个 `QSemaphore` 对象,每个线程在加载图片前申请一个信号量,加载完成后释放信号量。如果信号量已经全部被占用,则线程会阻塞在 `acquire()` 函数处,等待有空闲的信号量。这样就可以限制线程的并发数量,防止过多的线程同时加载图片导致系统资源耗尽。
阅读全文