PYBIND11: Внесите изменения в значение объекта класса в другом потоке c , когда интерпретатор python встроен и запущен в другом потоке

#python #c #multithreading #pybind11 #python-bindings

Вопрос:

Я просто печатаю значение car1.vehicle_id в python. Я хочу, чтобы он печатал «1234» в течение первых 2 секунд, а затем, когда значение изменится в другом потоке на «4543» , изменение должно вступить в силу в python. Возможно ли это или есть простой пример, который поможет мне в этом?

c

 #include lt;pybind11/embed.hgt; #include lt;stringgt; #include lt;threadgt; #include lt;chronogt; // Define namespace for pybind11 namespace py = pybind11;  class Vehiclee { // Access specifier public: Vehiclee(){}; ~Vehiclee() {} // Data Members int vehicle_id; std::string vehicle_name; std::string vehicle_color;  // Member Functions() void printname() { std::cout lt;lt; "Vehicle id is: " lt;lt; vehicle_id; std::cout lt;lt; "Vehicle name is: " lt;lt; vehicle_name; std::cout lt;lt; "Vehicle color is: " lt;lt; vehicle_color; } };  PYBIND11_EMBEDDED_MODULE(embeded, m){  py::class_(m, "Vehiclee") .def_readonly("vehicle_name", amp;Vehiclee::vehicle_name) .def_readonly("vehicle_color", amp;Vehiclee::vehicle_color) .def_readonly("vehicle_id", amp;Vehiclee::vehicle_id);  } py::scoped_interpreter python{}; Vehiclee car1;  void threadFunc() { sleep(2); std::coutlt;lt;"entering thread"; car1.vehicle_id = 4543; std::coutlt;lt;"Modified val in thread";  }  int main() { // Initialize the python interpreter  // Import all the functions from scripts by file name in the working directory auto simpleFuncs = py::module::import("simpleFuncs");  // Test if C   objects can be passed into python functions  car1.vehicle_id = 1234; std::thread t1(threadFunc); simpleFuncs.attr("simplePrint")(car1); t1.join(); return 0; }  

питон

 gt; import time  gt; import importlib  gt; import embeded gt;  gt; def simplePrint(argument):  gt; while(1):  gt; importlib.reload(embeded) gt; print(argument.vehicle_id) time.sleep(1)  

Выходной ток

всегда 1234

Требуемая производительность

 1234 (for first 2 secs) 4543 (after 2 secs)  

Ответ №1:

Вам нужно понять правила C для потоковой передачи. В C потоки могут работать намного лучше параллельно, чем в Python. Это связано с тем, что в C потоки по умолчанию выполняются полностью отдельно друг от друга, в то время как Python использует глобальную блокировку интерпретатора, которая вызывает большую синхронизацию потоков.

Итак, в этом случае вам действительно нужна синхронизация потоков, потому что потоки совместно используют переменную ( car1 ). Проблема в том, что .def_readonly скрывается некоторый шаблонный код, который не выполняет синхронизацию — имеет смысл, потому что какой объект он должен использовать для синхронизации?

Итак , что вам нужно сделать, это ввести методы получения и установки Vehicle и добавить a std::mutex . В каждом геттере и каждом сеттере вы блокируете и разблокируете этот мьютекс. Это легко сделать с помощью a std::scoped_lock — это автоматически разблокирует мьютекс, когда метод вернется.

Есть и другие варианты. Ибо vehicle_id вы могли бы использовать a std::atomic_int , но вам, вероятно, все равно понадобится метод получения. Я не думаю, что pybind понимает атомарные переменные.