为什么我的Python/C++代码使用Pybind11进行多线程会导致死锁?

问题描述 投票:0回答:1

我正在开发一个 Python 项目,出于性能原因,我需要将一些计算卸载到 C++。我正在使用 Pybind11 在 Python 和 C++ 之间建立桥梁。在我的场景中,我尝试运行多个 C++ 线程,这些线程调用回调函数来修改 Python 对象中的值。但是,我遇到了僵局,我不知道为什么。这是我的代码的简化版本:

Python代码:


import example
import threading

class MyClass:
    def __init__(self, value=0):
        self.value = value
        self.lock = threading.Lock()

    def python_callback(self, arg1: float, arg2: float) -> float:
        with self.lock:
            self.value += arg1
            self.value += arg2
        return float(self.value)

myclass = MyClass()

def cpp_thread():
    example.call_cpp_thread(myclass, 1.0, 1.0, 10000)

def python_thread():
    for i in range(40000):
        myclass.python_callback(1, 1)

# Create and start threads
thread1 = threading.Thread(target=cpp_thread)
thread2 = threading.Thread(target=python_thread)
thread1.start()
thread2.start()

# Wait for threads to complete
thread1.join()
thread2.join()

print(myclass.value)

C++代码:

#include <pybind11/pybind11.h>
#include <pybind11/functional.h>
#include <pybind11/stl.h>
#include <thread>

namespace py = pybind11;

void call_python_callback(py::object obj, float arg1, float arg2, int calltime) {
    for (int i = 0; i < calltime; i++) {
        obj.attr("python_callback")(arg1, arg2);
    }
}

void call_cpp_thread(py::object obj, float arg1, float arg2, int calltime) {
    std::thread t1(call_python_callback, obj, arg1, arg2, calltime);
    std::thread t2(call_python_callback, obj, arg1, arg2, calltime);
    std::thread t3(call_python_callback, obj, arg1, arg2, calltime);
    std::thread t4(call_python_callback, obj, arg1, arg2, calltime);
    t1.join();
    t2.join();
    t3.join();
    t4.join();
}

PYBIND11_MODULE(example, m) {
    m.def("call_python_callback", &call_python_callback, "Call a Python callback",
          py::arg("obj"), py::arg("arg1"), py::arg("arg2"), py::arg("calltime"));
    m.def("call_cpp_thread", &call_cpp_thread, "Call cpp thread",
          py::arg("obj"), py::arg("arg1"), py::arg("arg2"), py::arg("calltime"));
}

说明: Python 类 MyClass:它有一个方法 python_callback 可以修改对象的值。该方法使用threading.Lock进行保护,以确保属性值的线程安全。

C++函数call_python_callback:重复调用Python回调函数。调用python代码时会自动获取GIL

C++函数call_cpp_thread:它启动多个执行call_python_callback的线程。 问题:

当我运行代码时,会导致死锁。

我尝试在 cpp 中添加互斥锁来保护对 python 的调用。

python multithreading thread-safety deadlock pybind11
1个回答
0
投票

问题是这样的 当python调用cpp代码时。它尝试在 cpp 中创建线程。 cpp的主线程持有GIL并等待子线程完成(因为我在所有线程上调用.join函数)。

在子线程中需要GIL来执行python回调。

这导致了僵局。

如何解决: 在加入线程之前释放吉尔。

© www.soinside.com 2019 - 2024. All rights reserved.