简体   繁体   English

为什么在 Pybind11 中使用线程时会出现 memory 访问冲突?

[英]Why do I get memory access violation when using threads in Pybind11?

I created a C++ wrapper to access my Python modules.我创建了一个C++包装器来访问我的Python模块。 everything is working until I try to use threads in my application.一切正常,直到我尝试在我的应用程序中使用线程。
On my Python module there is a method which reads from a webcam (so its uses an infinite loop) and I send callbacks from C++ to get the image and other needed information from it.在我的Python模块上,有一个从网络摄像头读取数据的方法(因此它使用无限循环),我从C++发送回调以从中获取图像和其他所需信息。
Since we have a blocking method here, I decided to use threads.由于我们这里有一个阻塞方法,我决定使用线程。
The threading on Python part seems not to be working on the C++ side that is if I call the async counter part of the webcam_feed loop, none of my callbacks are actually executed (on python part the routines are all executed however, it seems it doesn't reach to C++ section somehow. I don't get any feedback in C++ side, however, on Python part, those routines responsible for executing the callbacks save the info to the disk so I know for sure they are executed). Python部分上的线程似乎在C++方面不起作用,即如果我调用webcam_feed循环的异步计数器部分,我的回调实际上都没有执行(在 Z23EEEB4347BDD23EEEB4347BDD23EEEB4347BDD23EEEB4347BDD23EEEB4347BDD23EEEB4347BDD23EEEB4347BDD256BFC6B7EE9A '无法以某种方式到达 C++ 部分。我在 C++ 方面没有得到任何反馈,但是,在 Python 部分,这些例程保存了负责执行它们的信息,因此我知道它们已执行信息。
I asked a separate question for it here .在这里问了一个单独的问题。
Therefore I decided to use the threading inside C++ client.因此我决定使用 C++ 客户端内部的线程。 However, whenever I execute the code (given below), I get an access violation whenever I want to use any methods after the thread is started.但是,每当我执行代码(如下所示)时,每当我想在线程启动后使用任何方法时都会遇到访问冲突。 Here are the sample callbacks I have for now:这是我现在拥有的示例回调:


void default_callback(bool status, std::string id, py::array_t<uint8_t>& img)
{
    auto rows = img.shape(0);
    auto cols = img.shape(1);
    auto type = CV_8UC3;

    cv::Mat img1(rows, cols, type, img.mutable_data());

    cv::imshow("from callback", img1);
    cv::waitKey(1);
    auto timenow = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now());
    std::cout << "\narg1: " << status << " arg2: " << id << " arg3: " << typeid(img).name() << " " << ctime(&timenow) << std::endl;
}

void default_c_callback_temporary(bool status, char* message)
{
    std::cout << "status is: " << status << " id/name: " << message << " ptr:" << "" << std::endl;
    std::ofstream myfile;
    myfile.open("example.txt");
    myfile << "Writing this to a file: " << status << message << std::endl;
    myfile.close();
}

And this is the actual test这是实际的测试

void thread_test_start(Core* core)
{
    try
    {
        core->SetCpuAffinity(2);
        core->AddCallback(default_callback);
        core->AddCallback_C_tmp(default_c_callback_temporary);
        //set true to run the async version (implemented in python)
        core->Start(false);
    }
    catch (const std::exception& ex)
    {
        std::cout << ex.what() << std::endl;
    }
}


int main()
{
    Core* core = new Core(false);
    std::thread t(thread_test_start, core);

    py::print(core->GetCallbacks());
    std::cout << "\nGet C Callbacks:\n";
    py::print(core->GetCallbacks_C_tmp());

    std::cout << "\nEverything done. press Enter to Exit";
    t.join();
    std::getchar();
    return 0;
}

The call to core->GetCallbacks() causes the memory access violation:core->GetCallbacks()的调用导致 memory 访问冲突:

Exception thrown at 0x000000006FCC6D80 (python36.dll) in TestDLL.exe: 0xC0000005: Access violation reading location 0x0000000000000010.

And here is a snapshot showing the access violation error inside VS2019:这是显示 VS2019 内部访问冲突错误的快照:
在此处输入图像描述

Doing something like this is also the same:做这样的事情也是一样的:


void thread_test_start2()
{
    try
    {
        Core* core = new Core(false);
        core->SetCpuAffinity(2);
        core->AddCallback(default_callback);
        core->AddCallback_C_tmp(default_c_callback_temporary);

        std::thread t(&Core::Start, core, false);
        py::print(core->GetCallbacks());
        std::cout << "\nGet C Callbacks:\n";
        py::print(core->GetCallbacks_C_tmp());
        t.join();
    }
    catch (const std::exception& ex)
    {
        std::cout << ex.what() << std::endl;
    }
}

results in:结果是:

Exception thrown at 0x000000006FCC0CDF (python36.dll) in TestDLL.exe: 0xC0000005: Access violation writing location 0x0000000000000020.

like the former one.像前一个。 Why am I getting this error?为什么我会收到此错误? Can we not use threading with Pybind11?我们不能在 Pybind11 中使用线程吗? What am I missing here?我在这里想念什么?

Here is a sample project to re-create this issue: https://workupload.com/file/6LmfRtbztHK这是重新创建此问题的示例项目: https://workupload.com/file/6LmfRtbztHK

The reason for memory access violations were due to trying to run methods using different threads. memory 访问冲突的原因是由于尝试使用不同的线程运行方法。 That is, all Pybind11 related methods (methods that use Pybind11) need to be executed under the very same thread it seems.也就是说,所有与 Pybind11 相关的方法(使用 Pybind11 的方法)都需要在看起来非常相同的线程下执行。
Therefore executing some portion of the code under one thread and trying to execute some other methods in the main thread will result in memory access violation.因此在一个线程下执行部分代码并尝试在主线程中执行一些其他方法将导致 memory 访问冲突。
In order to get around this, I ended up implementing a simple dispatcher in one callback where any method that needs to be run, first sets a flag, then each time the callback is run, the flag is checked and the corresponding method is run.为了解决这个问题,我最终在一个回调中实现了一个简单的调度程序,其中任何需要运行的方法,首先设置一个标志,然后每次运行回调时,检查标志并运行相应的方法。

int flag=0;
void callback(...)
{
    switch(flag)
    {
        case 1: //e.g. stop
            core->stop();
            break;
        case 2: // e.g. get_callbacks() 
            core->get_callbacks();
            break;
        case 3: 
            //some other op
            break;
        ....     
    }
    //reset flag
    flag = 0; 
}

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

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