【问题标题】:C++ std::thread terminate called without an active exception AbortedC++ std::thread 在没有活动异常的情况下终止调用已中止
【发布时间】:2020-03-06 17:18:59
【问题描述】:

我这里有一个代码,它从在单独的线程中运行视频捕获操作的摄像机捕获视频流。代码可以编译,但是当我尝试运行它时,我收到以下错误。

我做了一些研究,发现这个问题与th.join(); 的缺失有关,但是当用户通过按下q 键中断进程时,我已经这样做了。在那之前,代码应该继续在创建的线程中运行。所以这告诉我应该在其他地方加入线程。

如果我通过用VideoCaptureAsync::update(); 替换thread th(&VideoCaptureAsync::update, this); 并删除th.join(); 来删除线程,错误就会消失,但这显然违背了这段代码的目的。

输出

内部启动函数

(进程:10748):GStreamer-CRITICAL **:gst_element_get_state: 断言“GST_IS_ELEMENT(元素)”失败

内部启动函数

内部更新函数

在没有活动异常的情况下终止调用

内部读取函数

中止(核心转储)

代码

/*
* Asynchronous_video_capture.cpp
*
* Copyright (C) 2019 C. S. G.
*
* MIT License
*/

#include <iostream> // for standard I/O
#include <string>   // for strings
#include <opencv2/highgui.hpp>
#include <opencv2/core.hpp>     // Basic OpenCV structures (cv::Mat)
#include <opencv2/videoio.hpp>  // Video write
#include <opencv2/opencv.hpp>
#include <opencv2/core/utility.hpp>
#include <thread>
#include <tuple>

using namespace cv;
using namespace std;

void foo(bool &keep_run){
    cout << "Inside the thread: Interrupt flag = " << keep_run << endl;
    if (std::cin.get() == 'q') {
        keep_run = false;
        cout << "User Interrupted the process. Interrupt flag = " << keep_run << endl;
    }
}

class VideoCaptureAsync
{
private:
    VideoCapture cam;
    thread th;
    bool read_lock;
    Mat frame;
    Mat grabbed;
    bool isStarted;
public:
    void initiate(unsigned int camId, unsigned int width, unsigned int height, double fps);
    void start();       // a start function to create and start the thread
    void update();      // an update function that will be called asynchronously
    tuple<Mat, Mat> read();        // a read function that we will call from our code to retrieve a new frame.
    void stop();        // a stop function to stop (join) the thread
    void exit();        // an __exit__ function to clean up some resources.
};

void VideoCaptureAsync::initiate(unsigned int camId, unsigned int width, unsigned int height, double fps){
    cout << "Inside initiate function" << endl;
    cam.open(camId);
    if (!cam.isOpened())
    {
        cerr  << "Could not open the VideoCapture camera: " << camId << endl;
    }
    cam.set(CV_CAP_PROP_FRAME_WIDTH, width);
    cam.set(CV_CAP_PROP_FRAME_HEIGHT, height);
    cam.set(CAP_PROP_FPS, fps);

    isStarted = false;
    read_lock = false;
    VideoCaptureAsync::start();
}

void VideoCaptureAsync::start(){
    cout << "Inside start function" << endl;
    if (isStarted) {
        cout << "Asynchroneous video capturing has already been started" << endl;
    }
    isStarted = true; 
    thread th(&VideoCaptureAsync::update, this);
    //VideoCaptureAsync::update();
}

void VideoCaptureAsync::update(){
    cout << "Inside update function" << endl;
    while(isStarted){
        Mat frame_update;
        Mat grabbed_update;
        tie(frame_update, grabbed_update) = VideoCaptureAsync::read();
        if(!read_lock){
            frame_update.copyTo(frame);
            grabbed_update.copyTo(grabbed);
        }
    }
}

tuple<Mat, Mat> VideoCaptureAsync::read(){
    cout << "Inside read function" << endl;
    if (!read_lock){
        read_lock = true;
        Mat frame_read;
        cam.read(frame_read);
        Mat grabbed_read;
        read_lock = false;
        return make_tuple(frame_read, grabbed_read);
    }
}

void VideoCaptureAsync::stop(){
    cout << "Inside stop function" << endl;
    th.join();
    isStarted = false;
    read_lock = true;
}

void VideoCaptureAsync::exit(){
    cout << "Finished writing ..." << endl;
    cam.release();
}

int main(int argc, char *argv[]){

    const unsigned int camId = 1;
    const bool enableOutput = true;
    const unsigned int w = 1280;
    const unsigned int h = 720;
    double fps = 30.0;


    VideoCaptureAsync obj;
    obj.initiate(camId,w,h,fps);
    bool keep_running = true;
    thread th1(foo, std::ref(keep_running));
    Mat original_frame;

    while (keep_running) {
        std::tie(std::ignore, original_frame) = obj.read();

        if (enableOutput) {
            imshow("Retrieved Image", original_frame);
            waitKey(1000/fps);
        }
    }

    obj.stop();
    obj.exit();

}

【问题讨论】:

  • "没有 th.join(); 但是当用户按 q 键中断进程时我已经这样做了。" -- 如您所说,上述与q 键处理相关的代码的哪一部分在正在运行的线程上执行join()?显示的代码没有这样的事情。
  • @SamVarshavchik 确实如此。按 q 退出 main() 内的 while 循环,然后执行 VideoCaptureAsync::stop() ,其中包含 th.join() 。
  • 该类的th 成员与实际执行线程main() 中的th1 对象有什么关系? th.join()th1 对象完全没有任何作用,这是您真正需要停止的对象。似乎没有任何由th 启动的执行线程,因此调用它的join() 看起来并没有加入任何东西。
  • @SamVarshavchik 好的,我在 obj.stop() 之前也停止了 th1,但这并没有解决问题。我确定问题出在th,而不是th1

标签: c++ multithreading opencv oop c++17


【解决方案1】:

在您的start() 方法中:

thread th(&VideoCaptureAsync::update, this);

此语句在称为thstart() 方法中创建一个新的本地对象,一个全新的、刚下线的std::thread 对象,并以创建新执行线程的方式构造它。

紧接着,start() 返回。这会破坏这个本地对象,调用它的析构函数,并导致你的异常。

您的明显意图是使用th 类成员来创建一个新的执行线程,而不是在start() 方法中创建一个新的本地对象。但是上面的 C++ 语法是一个声明。它声明了一个新对象,当在函数中使用时,它会创建一个新的本地对象(在自动范围内),该对象在范围结束时会自动销毁。这就是 C++ 的工作原理。

为了让新的执行线程从你现有的类成员开始:

th=thread{&VideoCaptureAsync::update, this};

(使用现代 C++ 的统一初始化语法)。如需更多信息,请参阅“Delayed start of thread in C++11”。

【讨论】:

    猜你喜欢
    • 2014-10-14
    • 2016-10-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-09-09
    • 2021-07-02
    • 2021-10-10
    • 2011-11-14
    相关资源
    最近更新 更多