" Project.exe触发了一个断点"实现多线程后

时间:2017-07-27 20:53:31

标签: c++ multithreading

我有一个正常工作的Visual Studio项目,直到我尝试实现multithreading。该项目从GigE相机获取图像,并且在获取10个图像之后,从所获取的图像中制作视频。

程序流程使得程序在制作视频时没有获取图像。我想改变它,所以我创建了另一个从图像中制作视频的线程。我想要的是该程序将连续获取图像,获取10个图像后,另一个并行运行的线程将制作视频。这将持续到我停止程序,获取10张图像,这10幅图像中的视频并行制作,同时获取下10张图像,等等。

我之前没有创建threads所以我按照this website上的教程进行了操作。与网站类似,我为保存视频的thread创建了function。创建视频的function将10张图片作为vector参数。我在join函数终止的行之前的这个线程上执行main

为清楚起见,这里是我实施的伪代码:

#include ...
#include <thread>

using namespace std;

thread threads[1];
vector<Image> images;

void thread_method(vector<Image> & images){
    // Save vector of images to video
    // Clear the vector of images
}

int main(int argc, char* argv[]){
    // Some stuff
    while(TRUE)
    {
        for (int i = 0; i < 10; i++)
        {    
            //Acquire Image
            //Put image pointer in images vector named images
        }
        threads[0] = thread(thread_method, images)
    }

    // stuff

    threads[0].join();

    cout << endl << "Done! Press Enter to exit..." << endl;
    getchar();

    return 0;
}

当我现在运行该项目时,会弹出一条消息,指出Project.exe已触发断点。该项目在report_runtime_error.cpp中的static bool __cdecl issue_debug_notification(wchar_t const* const message) throw()中断。

我在控制台上打印了一些cout消息,以帮助我了解正在发生的事情。会发生什么是程序获取10张图像,然后保存视频的thread开始运行。由于有10个图像,因此必须将10个图像附加到视频中。在第二次获取10张图像后,弹出Project.exe触发断点的消息,此时并行线程仅将第一张获取的图像集中的6张图像附加到视频中。

输出包含多行thread XXXX has exited with code 0,之后输出显示

Debug Error!

Program: ...Path\Program.exe

abort() has been called

(Press Retry to debug the application)

Program.exe has triggered a breakpoint.

2 个答案:

答案 0 :(得分:1)

我无法在评论中解释这一切。我在这里放弃它,因为看起来OP正朝着一些糟糕的方向前进,我想在悬崖前把他赶走。 Caleth已经抓住了大爆炸并提供了一个避免它的解决方案,但是爆炸只是OP的一个症状,并且detach的解决方案有点值得怀疑。

using namespace std;

Why is "using namespace std" considered bad practice?

thread threads[1];

数组1几乎没有意义。如果我们不知道将有多少线程,请使用vector。此外,没有充分理由将其作为全局变量。

vector<Image> images;

同样,没有充分理由认为这是全球性的,而且很多原因都不是。

void thread_method(vector<Image> & images){

通过引用传递可以为您节省一些复制,但是A)您无法复制引用和线程复制参数。好的,所以使用指针或std::ref。你可以复制那些。但是你通常不想这样做。问题1:使用相同数据的多个线程?最好只读或防止并发修改。这包括生成vector的线程。 2.参考文献仍然有效吗?

    // Save vector of images to video
    // Clear the vector of images
}

int main(int argc, char* argv[]){
    // Some stuff
    while(TRUE)
    {
        for (int i = 0; i < 10; i++)
        {    
            //Acquire Image
            //Put image pointer in images vector named images
        }
        threads[0] = thread(thread_method, images)

Caleth涵盖的原因很糟糕。加images不断增长。第一个线程,即使被复制,也有十个元素。第二个是前10个加上另外10个。这很奇怪,可能不是OP想要的。对此vector的引用或指针是致命的。 vector将在其他线程使用它时调整大小,使旧数据存储无效并使其无法安全迭代。

    }

    // stuff

    threads[0].join();

Caleth所涵盖的理由错误

    cout << endl << "Done! Press Enter to exit..." << endl;
    getchar();

    return 0;
}

加入线程的解决方案与几乎没有解决“使用std::string”的每个Stack Overflow问题相同:使用std::vector

#include <iostream>
#include <vector>
#include <thread>


void thread_method(std::vector<int> images){
    std::cout << images[0] << '\n'; // output something so we can see work being done.
    // we may or may not see all of the numbers in order depending on how 
    // the threads are scheduled.    
}

int main() // not using arguments, leave them out.
{
    int count = 0; // just to have something to show

    // no need for threads to be global.
    std::vector<std::thread> threads; // using vector so we can store multiple threads

    // Some stuff
    while(count < 10) // better-defined terminating condition for testing purposes
    {
        // every thread gets its own vector. No chance of collisions or duplicated 
        // effort
        std::vector<int> images; // don't have Image, so stubbing it out with int
        for (int i = 0; i < 10; i++)
        {
            images.push_back(count);
        }
        // create and store thread.
        threads.emplace_back(thread_method,std::move(images));
        count ++;
    }

    // stuff

    for (std::thread &temp: threads) // wait for all threads to exit
    {
        temp.join();
    }

    // std::endl is expensive. It's a linefeed and s stream flush, so save it for 
    // when you really need to get a message out immediately
    std::cout << "\nDone! Press Enter to exit..." << std::endl; 

    char temp;
    std::cin >>temp; // sticking with standard librarly all the way through

    return 0;
}

更好地解释

threads.emplace_back(thread_method,std::move(images));

这在thread threadsemplace_back创建了thread_methodimages会使用images的副本调用std::move。很有可能编译器会认识到这是$(".div-intro").on('inview', function(event, isInView) { if (isInView) { // $(".div").css('visibility','initial'); }else{ console.log("error"); } }); .div { visibility:hidden;} 这个特定实例的结束并消除了复制,但如果没有,[DllImport("setupapi.dll", SetLastError = true)] public static extern int CM_Get_Device_ID(uint dnDevInst, StringBuilder Buffer, int BufferLen, int ulFlags = 0); 应该给它提示。

答案 1 :(得分:0)

你是overwriting while循环中的一个线程。如果它仍在运行,程序将中止。您必须加入或分离每个线程值。

你可以改为

#include // ...
#include <thread>

// pass by value, as it's potentially outliving the loop
void thread_method(std::vector<Image> images){
    // Save vector of images to video
}

int main(int argc, char* argv[]){
    // Some stuff
    while(TRUE)
    {
        std::vector<Image> images; // new vector each time round

        for (int i = 0; i < 10; i++)
        {    
            //Acquire Image
            //Put image pointer in images vector named images
        }
        // std::thread::thread will forward this move
        std::thread(thread_method, std::move(images)).detach(); // not join
    }

    // stuff

    // this is somewhat of a lie now, we have to wait for the threads too
    std::cout << std::endl << "Done! Press Enter to exit..." << std::endl;
    std::getchar();

    return 0;
}