【问题标题】:tbb concurrent_bounded_queue multiple threads accesstbb concurrent_bounded_queue 多线程访问
【发布时间】:2016-10-25 03:44:20
【问题描述】:

我有以下代码:

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 线程中:

线程A:

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;
}

在另一个线程中:

线程B:

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 响应就越慢。

谁能帮忙解释一下原因?有办法解决吗?

【问题讨论】:

    标签: c++ multithreading qt tbb


    【解决方案1】:

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

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

    特别是尝试交换如下操作:

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

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

    【讨论】:

    • camera_queue_ (concurrent_bounded_queue with capacity 1 ) 用于从实时视频中获取图像数据。而image_queue_(容量为1的concurrent_bounded_queue)用于显示或保存操作。可能的死锁在哪里?我分别使用了两个并发队列。你能指出来吗?谢谢。
    • 发出 imageReady() 信号只是为了调用 Producer 实例从 image_queue_ 获取图像并在主线程中显示。
    • 现在假设 Producer 队列中还有一个 item,按照你的操作顺序,push 会阻塞,Producer 不会被调用。
    • 但是在Worker实例中,有一个camera_queue_.pop操作。
    • 从这里的代码中并不清楚哪个线程执行什么。我不会解析它。我的建议是检查同步的顺序,记住 push 和 pop 都可以阻塞
    猜你喜欢
    • 2021-07-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-06-02
    • 2014-05-01
    • 2021-06-07
    • 1970-01-01
    相关资源
    最近更新 更多