I have an cpp file write with pybind11 extension and then I compile it and import to python as module example
My purpose is to test if I can run cpp concurrently with python without any lock.
Normally, because of GIL when you run multithread python that access the same object, you do not need a lock
<code>#include <pybind11/pybind11.h>
#include <pybind11/functional.h>
#include <pybind11/stl.h>
#include <Python.h>
namespace py = pybind11;
std::mutex mtx;
void call_python_object(py::object obj, float arg1, float arg2) {
obj.attr("my_python_function")(arg1,arg2);
}
PYBIND11_MODULE(example, m) {
m.def("call_python_object", &call_python_object, "Call a Python object");
}
</code>
<code>#include <pybind11/pybind11.h>
#include <pybind11/functional.h>
#include <pybind11/stl.h>
#include <Python.h>
namespace py = pybind11;
std::mutex mtx;
void call_python_object(py::object obj, float arg1, float arg2) {
obj.attr("my_python_function")(arg1,arg2);
}
PYBIND11_MODULE(example, m) {
m.def("call_python_object", &call_python_object, "Call a Python object");
}
</code>
#include <pybind11/pybind11.h>
#include <pybind11/functional.h>
#include <pybind11/stl.h>
#include <Python.h>
namespace py = pybind11;
std::mutex mtx;
void call_python_object(py::object obj, float arg1, float arg2) {
obj.attr("my_python_function")(arg1,arg2);
}
PYBIND11_MODULE(example, m) {
m.def("call_python_object", &call_python_object, "Call a Python object");
}
The python file is as follow
<code>import pybind11
import example
import threading
class MyClass:
def __init__(self,value=0):
self.value = value
def my_python_function(self, arg1: float, arg2: float) -> float:
self.value+=arg1
self.value+=arg2
return float(self.value)
myclass = MyClass()
def cpp_thread():
for i in range(50000):
example.call_python_object(myclass,1.0,1.0)
def python_thead():
for i in range(50000):
myclass.my_python_function(1,1)
thread1 = threading.Thread(target=cpp_thread)
thread1.start()
thread2 = threading.Thread(target=python_thead)
thread2.start()
thread1.join()
thread2.join()
print(myclass.value)
</code>
<code>import pybind11
import example
import threading
class MyClass:
def __init__(self,value=0):
self.value = value
def my_python_function(self, arg1: float, arg2: float) -> float:
self.value+=arg1
self.value+=arg2
return float(self.value)
myclass = MyClass()
def cpp_thread():
for i in range(50000):
example.call_python_object(myclass,1.0,1.0)
def python_thead():
for i in range(50000):
myclass.my_python_function(1,1)
thread1 = threading.Thread(target=cpp_thread)
thread1.start()
thread2 = threading.Thread(target=python_thead)
thread2.start()
thread1.join()
thread2.join()
print(myclass.value)
</code>
import pybind11
import example
import threading
class MyClass:
def __init__(self,value=0):
self.value = value
def my_python_function(self, arg1: float, arg2: float) -> float:
self.value+=arg1
self.value+=arg2
return float(self.value)
myclass = MyClass()
def cpp_thread():
for i in range(50000):
example.call_python_object(myclass,1.0,1.0)
def python_thead():
for i in range(50000):
myclass.my_python_function(1,1)
thread1 = threading.Thread(target=cpp_thread)
thread1.start()
thread2 = threading.Thread(target=python_thead)
thread2.start()
thread1.join()
thread2.join()
print(myclass.value)
Normally, the result should be 200000 but it is not.
Why there is an race condition, does that mean pybind11 does not hold the GIL when execute python code