我在整合上有问题增压信号2在我现有的C++ LIB中,我已经暴露了boost.python. 在
我有一个用std::shared_ptr
向python公开的类。
这个类应该能够在某些事件上发出一些信号。
因此,我公开了一个connect_slot
函数,它以boost::python::object
作为参数。如果我在连接一个插槽后直接发出一个信号,一切都会正常工作,但是如果类在以后发出信号,我就会收到分段错误。在
我认为这可能与c++库中的线程有关(它也在使用boos::asio等)
下面是一些代码片段:
我的class.h:
public:
typedef boost::signals2::signal<void (std::shared_ptr<int>)> signal_my_sig;
void connect_slot(boost::python::object const & slot);
private:
signal_my_sig m_sig;
在我的class.cpp以下内容:
^{pr2}$我用一个定制的python函数调用python中的MyClass::connect_slot函数,如下所示:
def testfunc(some_int):
print("slot called")
m = myext.MyClass()
m.connect_slot(testfunc)
在MyClass::some_later_event
中引发的分段错误的回溯(使用gdb)如下所示:
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
[New Thread 0x7ffff3c37700 (LWP 20634)]
Program received signal SIGSEGV, Segmentation fault.
[Switching to Thread 0x7ffff3c37700 (LWP 20634)]
0x00000000004f7480 in PyObject_Call ()
(gdb)
(gdb) backtrace
#0 0x00000000004f7480 in PyObject_Call ()
#1 0x00000000004f7aa6 in PyEval_CallObjectWithKeywords ()
#2 0x000000000049bd84 in PyEval_CallFunction ()
#3 0x00007ffff5375d9f in boost::python::call<boost::python::api::object, int>
(callable=0x7ffff7ed4578, a0=@0x7ffff3c35b34: 5)
at /usr/local/boost_1_55_0/boost/python/call.hpp:66
#4 0x00007ffff5374b81 in boost::python::api::object_operators<boost::python::api::object>::operator()<int> (this=0x9e3bf0, a0=@0x7ffff3c35b34: 5)
at /usr/local/boost_1_55_0/boost/python/object_call.hpp:19
#5 0x00007ffff5373658 in boost::detail::function::void_function_obj_invoker1<boost::python::api::object, void, int>::invoke (function_obj_ptr=..., a0=5)
at /usr/local/boost_1_55_0/boost/function/function_template.hpp:153
#6 0x00007ffff5378a3c in boost::function1<void, int>::operator() (
this=0x9e3be8, a0=5)
at /usr/local/boost_1_55_0/boost/function/function_template.hpp:767
#7 0x00007ffff53781f9 in boost::signals2::detail::call_with_tuple_args<boost::signals2::detail::void_type>::m_invoke<boost::function<void (int)>, 0u, int&>(void*, boost::function<void (int)>&, boost::signals2::detail::unsigned_meta_array<0u>, std::tuple<int&>) const (this=0x7ffff3c35c7f, func=..., args=...)
at /usr/local/boost_1_55_0/boost/signals2/detail/variadic_slot_invoker.hpp:92
有什么想法吗?
感谢Tanner Sansbury在this帖子上链接了他的答案。这解决了我的问题,只是我不能调用接受参数的信号。在
我通过编辑py_slot类解决了这个问题:
boost::bind调用如下所示:
^{pr2}$如果从一个不显式管理Global Interpreter Lock(吉尔)的C++线程调用^ {CD1>},则会导致未定义的行为。在
< H2> Python和C++线程。
让我们考虑C++线程与Python交互的情况。例如,可以设置一个C++线程,通过^ {CD3}}在一段时间后调用^ {< CD2> }的信号。在
这个例子可能会涉及很多,所以让我们从基础知识开始:Python的GIL。简而言之,GIL是围绕着翻译的互斥体。如果一个线程正在做任何影响python托管对象的引用计数的操作,那么它需要获得GIL。在GDB回溯中增压信号2library可能试图在没有GIL的情况下调用Python对象,导致崩溃。虽然管理GIL相当简单,但它很快就会变得复杂。在
首先,该模块需要Python初始化GIL进行线程化。在
为了方便起见,让我们创建一个简单的类来帮助通过作用域管理GIL:
^{pr2}$让我们确认C++线程何时需要吉尔:
boost::signals2::signal
可以创建连接对象的附加副本,就像调用信号时一样。在boost::signals2::signal
连接的Python对象。回调肯定会影响python对象。例如,提供给__call__
方法的self
参数将增加或减少对象的引用计数。在MyClass
类。以下是基于原始代码的基本模型类:
作为C++线程,可能调用^ {CD2>}的信号,其生存期至少为线程的长度。一个很好的人选是Boost.Python使用
boost::shared_ptr
管理MyClass
。在boost::signals2::signal
与python对象交互。boost::signals2::signal
在调用时可能会生成副本。另外,可能有连接到信号的C++插槽,所以在调用Python插槽时只锁定吉尔是理想的。但是,signal
并没有提供钩子来允许我们在创建slot副本或调用slot之前获取GIL。在为了避免}。在
signal
创建boost::python::object
槽的副本,可以使用一个包装类来创建boost::python::object
的副本,以便引用计数保持准确,并通过shared_ptr
管理副本。这允许signal
自由地创建shared_ptr
的副本,而不是在没有GIL的情况下复制{这个GIL安全槽可以封装在helper类中。在
一个helper函数将向Python公开,以帮助调整类型。在
更新后的绑定公开了helper函数:
线本身。
线程的功能相当基本:它休眠然后调用信号。然而,理解GIL的背景是很重要的。在
注意,
MyClass_event_in_thread
可以表示为lambda,但是在lambda中解压模板包在某些编译器上不起作用。并更新
MyClass
绑定。在最终解决方案如下:
以及测试脚本:
结果如下:
相关问题 更多 >
编程相关推荐