【问题标题】:Access violation in Mat queueMat队列中的访问冲突
【发布时间】:2021-05-21 13:14:17
【问题描述】:

我正在编写一个从外部库接收帧日期的生产者/消费者代码。

每一帧都是从一个在并行线程中运行的外部库的回调函数中读取的,并被推送到一个 Mat 队列中。我创建了另一个在不同线程中运行的函数,该线程读取并弹出每一帧。

问题是我在尝试从队列中读取帧数据时收到“访问冲突读取位置”。

我在全局声明这些变量:

queue<Mat> matQ;
OnFrameDataReceivedCB videoCB;
OnDeviceConnectStatusCB connectCB;
guide_usb_video_mode_e videoMode;
int width = 640;
int height = 512;
std::mutex mu;

下面是推送每帧数据的回调函数代码:

void OnVideoCallBack(const guide_usb_frame_data_t data) //callback function
{
    if (data.frame_rgb_data_length > 0)
    {
        // Send the displayed data directly
        unsigned char* rgbData;
        Mat frame;
        Size size = Size(width, height);
        rgbData = data.frame_rgb_data;
        frame = Mat(size, CV_8UC3, rgbData, Mat::AUTO_STEP);


        if (mu.try_lock())
        {
            printf("producing...\n");
            matQ.push(frame);
            printf("free producing\n");
            mu.unlock();
        }

    }
}

这是从队列中读取的函数:

void OnHandleVideoData()
{
    while (true)
    {
        try
        {
            if (matQ.size() <= 0)
            {
                chrono::milliseconds duration(200);
                this_thread::sleep_for(duration);
                continue;
            }


            if (mu.try_lock())
            {
                if (matQ.size() > 0)
                {
                    printf("consuming...\n");
                    Size size = Size(width, height);
                    Mat frame = Mat(size, CV_8UC3);
                    frame = matQ.front().clone();
                    matQ.pop();
                    imwrite("frame.jpg", frame); //the access violation exception is thrown on this line
                    printf("free consuming\n");
                    mu.unlock();
                }
            }
            
        }
        catch (...)
        {
            
        }
    }

}

我也尝试将 unsigned char* rgbData 数组放入队列而不是 Mat,但我得到了同样的错误。

我错过了什么?

【问题讨论】:

    标签: c++ multithreading opencv queue mutex


    【解决方案1】:

    您应该在收到帧时立即尝试克隆:

    frame = Mat(size, CV_8UC3, rgbData, Mat::AUTO_STEP).clone();

    而不是那里:

    frame = matQ.front()/*.clone()*/;

    【讨论】:

    • 如果它解释了为什么 OP应该这样做,这个答案会更有用。
    • 为了后代:似乎rgbData 指向的数据在OnVideoCallBack() 结束和下一个尝试使用它的OnHandleVideoData() 调用之间的某个位置被释放。这是有问题的,因为cv::Mat 构造函数默认情况下不会从外部缓冲区深度复制数据,而只是指向它并信任用户保持分配它。如果不再存在,那就是UB,所以很可能是SegFault。因此,立即克隆它是安全的。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多