TBB concurrent_bounded_queue多线程访问

tbb concurrent_bounded_queue multiple threads access

本文关键字:多线程 访问 queue bounded concurrent TBB      更新时间:2023-10-16

我有以下代码:

tbb::concurrent_bounded_queue<Image> camera_queue_;
camera_queue_.set_capacity(1);
struct Image
{
    int hour_;
    int minute_;
    int second_;
    int msec_;
    QImage image_;
    Image(){hour_ = -1; minute_ = -1; second_ = -1; msec_ = -1; image_ = QImage();}
    Image& operator=(Image const& copy)
    {
        this->hour_ = copy.hour_;
        this->minute_ = copy.minute_;
        this->second_ = copy.second_;
        this->msec_ = copy.msec_;
        this->image_ = copy.image_;
        return *this;
    }
};

在Qt线程中:

ThreadA:

tbb::concurrent_bounded_queue<Image> image_queue_;
image_queue_.set_capacity(1);
Image cur_image_;
void Worker::process() {
    while(1)
    {
        if(quit_)
            break;
        {
            camera_queue_.pop(cur_image_);
            image_queue_.push(cur_image_);
        }
        emit imageReady();
    }
    emit finished();
}
Image Worker::getCurrentImage()
{
    Image tmp_image;
    image_queue_.pop(tmp_image);
    return tmp_image;
}

在另一个线程中:

ThreadB:

Producer::Producer(){
    work_ = new Worker();
    work_->moveToThread(workerThread_);
    QObject::connect(workerThread_, &QThread::finished, work_, &QObject::deleteLater);
    QObject::connect(this, &Producer::operate, work_, &Worker::process);
    QObject::connect(work_, &Worker::imageReady, this, &Producer::displayImage);
    QObject::connect(this, &Producer::stopDecode, work_, &Worker::stop);
    workerThread_->start();
    emit operate();
}
void Producer::process() {
    while(1)
    {
        if(quit_)
            break;
        {
            camera_queue_.push(GetImage());
        }
    }
}

void Producer::displayImage()
{
    Image tmp = std::move(work_->getCurrentImage());
    widget_->showImage(tmp.image_);
}

然而,在主线程中,我有一个函数,使用户能够单击按钮来获取当前图像:

bool Producer::SaveImage()
{
    Image img = std::move(work_->getCurrentImage());
    std::string fileName = std::to_string(img.hour_) + "-" + std::to_string(img.minute_) + "-" + std::to_string(img.second_) + "-" + std::to_string(img.msec_/1000) + ".jpg";
    std::string outFileName = folder + "/" + fileName;
    return img.image_.save(QString::fromStdString(outFileName));
}

问题是:

当用户不单击按钮调用Producer::SaveImage()时,图像解码和显示会顺利运行。但是当用户调用Producer::SaveImage()时,整个程序将卡住(卡顿现象?)GUI响应变得不那么流畅了。用户调用SaveImage的次数越多,GUI响应就越慢。

有谁能解释一下吗?有办法解决这个问题吗?

为什么要使用并发队列?看起来有一个同步机制,你主要依靠它,而不是使用concurrent_queue进行同步和通信,因为它应该。

问题是,当您设置capacity = 1时,concurrent_bounded_queue的两个操作将阻塞,直到队列中有足够的项目空间。例如,如果队列中已经包含一个项目,则push操作将阻塞。由于您使用另一种通知机制控制线程,因此可能会捕获死锁。

特别是,尝试像下面这样交换操作:

    camera_queue_.pop(cur_image_);
    emit imageReady();
    image_queue_.push(cur_image_);

这应该准备接收图像的线程(如果我理解正确的话),并且它将阻塞其image_queue_.pop()方法,然后该线程将放置新图像并解除对接收者的阻塞。可能还有其他类似的问题,所以,请重新考虑所有的同步。