Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Jupyter Kernel Notebook Dies After Starting Threaded Class #434

Closed
MasterBe opened this issue Apr 28, 2024 · 4 comments
Closed

Jupyter Kernel Notebook Dies After Starting Threaded Class #434

MasterBe opened this issue Apr 28, 2024 · 4 comments

Comments

@MasterBe
Copy link

MasterBe commented Apr 28, 2024

I am using Boost Python to expose a function that holds an internal thread, the class has start and stop functions that only control an internal loop. The code for MyClass is:

#include <iostream>
#include <atomic>
#include <thread>
#include <boost/make_shared.hpp>
#include <boost/python.hpp>
#include <boost/python/module.hpp>
#include <boost/python/make_constructor.hpp>

class MyClass
{
private:
    std::atomic<bool> running_;
    std::thread worker_;
    std::function<std::string(std::string)> m_op;


    void printMessage()
    {
        std::string s = "hello";
        while (running_)
        {
            s = m_op(s);
            std::this_thread::sleep_for(std::chrono::seconds(1));
        }
    }

public:
    MyClass() : running_(false) {}
    MyClass(const std::function<std::string(std::string)>& op) : running_(false), m_op(op) {}

    void start()
    {
        if (!running_)
        {
            running_ = true;
            worker_ = std::thread(&MyClass::printMessage, this);
        }
    }

    void stop()
    {
        if (running_)
        {
            running_ = false;
            worker_.join();
        }
    }
};

I then create a helper function to pass a callback as:

template<class output_tp, class... input_tps>
struct function_helper
{
    function_helper(const boost::python::object& op) : m_op(op) {}

    output_tp operator()(input_tps&&... args)
    {
        return boost::python::call<output_tp>(m_op.ptr(), std::forward<input_tps>(args)...);
    }

private:
    boost::python::object m_op;
};

boost::shared_ptr<MyClass> makeMakeClass(const boost::python::object& obj)
{
    return boost::make_shared<MyClass>(function_helper<std::string, std::string>(obj));
}

I then create my module:

BOOST_PYTHON_MODULE(draft)
{
    using namespace boost::python;

    class_<MyClass, bases<>, boost::shared_ptr<MyClass>, boost::noncopyable>("MyClass")
        .def("__init__", make_constructor(makeMakeClass))
        .def("start", &MyClass::start)
        .def("stop", &MyClass::stop);
}

I use the draft module in jupyter as follows attached

jupyter

The first run causes a crash as in

kernel

The second run is not throwing but produces nothing. Could you please help me make this work.

@MasterBe
Copy link
Author

UPDATE
I figured a partial source of the problem, this line boost::python::call is what is causing issues, wondering if it's a memory thing when copying const boost::python::object& op. Still stuck on how to make to the above work though.

@MasterBe
Copy link
Author

MasterBe commented May 5, 2024

@stefanseefeld could you please take a look at the above. Still blocked on this for days :)

@stefanseefeld
Copy link
Member

stefanseefeld commented May 6, 2024 via email

@MasterBe
Copy link
Author

@stefanseefeld Thanks very much for the hint. Problem solved it was indeed acquiring/ releasing the GIL

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants