Skip to content

Calling python function from thread created in C++ #1723

@banasraf

Description

@banasraf

I encountered a problem when trying to implement functionality similar to that on the snippet.

#include <pybind11/pybind11.h>
#include <iostream>
#include <thread>
#include <future>

namespace py = pybind11;

void hello() {
  std::cout << "hello\n";
}

struct Executor {

  void execute() {
    auto func = channel.get_future().get();
    func();
  }

  explicit Executor(py::object callback): callback(std::move(callback)), channel(), worker([this]{execute();}) {
  }

  void run() {
    pybind11::gil_scoped_release release{};
    channel.set_value(callback);
  }

  py::object callback;
  std::promise<py::object> channel;
  std::thread worker;

  ~Executor() {
    worker.join();
  }
};

PYBIND11_MODULE(pymodule, m) {
  m.def("hello", &hello, "Say hello");
  py::class_<Executor>(m, "Executor")
      .def(py::init<py::object>())
      .def("run", &Executor::run);
}

testing it with this python code:

import pymodule

def bye():
    print('bye')

if __name__ == '__main__':
    pymodule.hello()
    ex = pymodule.Executor(bye)
    ex.run()

The behavior is nondeterministic. For some runs it goes without any error and sometimes it ends with SEGFAULT. I saw similar issues here but none of the solutions worked for me. I tried to put gil_scoped_acquire and gil_scoped_release in every possible combination but in the result the python function was not called without any error, or just segmentation fault happened.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions