简体   繁体   English

C++ std::thread 终止调用而没有活动异常已中止

[英]C++ std::thread terminate called without an active exception Aborted

I have a code here that captures the video stream from a camera running the video capture operation in a separate thread.我这里有一个代码,它从在单独线程中运行视频捕获操作的相机捕获视频 stream。 The code compiles but when I try to run it I am receiving the following error.代码可以编译,但是当我尝试运行它时,我收到以下错误。

I did some research and found out that this problem is related to the absence of th.join();我做了一些研究,发现这个问题与缺少th.join();相关。 but I already do this when the user interrupts the process by pressing the q key.但是当用户通过按q键中断该过程时,我已经这样做了。 Until then, the code should keep on running in the created thread.在那之前,代码应该继续在创建的线程中运行。 So this tells me that I should join the thread somewhere else.所以这告诉我应该在其他地方加入线程。

If I remove the thread by replacing thread th(&VideoCaptureAsync::update, this);如果我通过替换thread th(&VideoCaptureAsync::update, this); with VideoCaptureAsync::update();使用VideoCaptureAsync::update(); and deleting th.join();并删除th.join(); , the error goes away but this obviously defeats the purpose of this code. ,错误消失了,但这显然违背了这段代码的目的。

Output Output

Inside initiate function内部启动 function

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

Inside start function内部启动 function

Inside update function内部更新 function

terminate called without an active exception在没有活动异常的情况下调用终止

Inside read function内读 function

Aborted (core dumped)中止(核心转储)

Code代码

/*
* 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();

}

In your start () method:在您的start () 方法中:

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

This statement creates a new local object in the start() method called th , a brand new, fresh off the assembly line, std::thread object, and constructs it in a manner that creates a new execution thread.该语句在名为thstart()方法中创建了一个新的本地 object,一个全新的、刚下线的std::thread object,并以创建新执行线程的方式构造它。

Immediately afterwards, start() returns.紧接着, start()返回。 This destroys this local object, invoking its destructor, and resulting in your exception.这会破坏这个本地 object,调用它的析构函数,并导致您的异常。

Your obvious intent is to use the th class member in order to create a new execution thread, instead of creating a new local object in the start() method.您的明显意图是使用th成员来创建新的执行线程,而不是在start()方法中创建新的本地 object 。 But the above C++ syntax is a declaration.但是上面的 C++ 语法是一个声明。 It declares a new object, and when used in side a function it creates a new local object (in automatic scope), that gets automatically destroyed at the end of the scope. It declares a new object, and when used in side a function it creates a new local object (in automatic scope), that gets automatically destroyed at the end of the scope. That's how C++ works.这就是 C++ 的工作原理。

In order to have the new execution thread started from your existing class member:为了让新的执行线程从您现有的 class 成员开始:

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

(using modern C++'s uniform initialization syntax). (使用现代 C++ 的统一初始化语法)。 For more information see " Delayed start of thread in C++11 ".有关详细信息,请参阅“ C++11 中的线程延迟启动”。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM