【问题标题】:Cython weakref to cdef class stored in C objectCython 对存储在 C 对象中的 cdef 类的弱引用
【发布时间】:2019-02-08 13:13:52
【问题描述】:

我正在尝试为 linphone 库编写 Cython 包装器,但我遇到了一个问题:我想将代表我的 C 对象的 Python 对象的弱引用存储在 C 对象中。

这是我的包装:

cdef void on_global_state_changed_cbs(LinphoneCore *lc, LinphoneGlobalState gstate, const char *message):
    print('Internal Callback : ' + str(gstate) + ' : ' + message)
    cbs = linphone_core_get_current_callbacks(lc)
    callbacks = CoreCallbacks.from_ptr(cbs)
    if callbacks.global_state_cb is not None:
        core = Core.from_ptr(lc)
        callbacks.global_state_cb(core, gstate, message)

ctypedef struct LinphoneCoreCbs:
    pass

cdef class CoreCallbacks:
    cdef object __weakref__
    cdef LinphoneCoreCbs *ptr
    cpdef global_state_cb

    @staticmethod
    cdef CoreCallbacks from_ptr(LinphoneCoreCbs *_ptr, take_ref = True):
        cdef CoreCallbacks coreCbs
        user_data = belle_sip_object_data_get(<belle_sip_object_t *>_ptr, 'python_user_data')

        if user_data is not NULL:
            tmpWRef = <object>user_data
            print tmpWRef
            coreCbs = tmpWRef()
            if coreCbs is None:
                coreCbs = CoreCallbacks.__new__(CoreCallbacks)
                coreCbs.ptr = linphone_core_cbs_ref(_ptr) if take_ref else _ptr
        else:
            coreCbs = CoreCallbacks.__new__(CoreCallbacks)
            coreCbs.ptr = linphone_core_cbs_ref(_ptr) if take_ref else _ptr

        print coreCbs
        wref = weakref.ref(coreCbs)
        print wref
        belle_sip_object_data_set(<belle_sip_object_t *>_ptr, 'python_user_data', <void *>wref, NULL)
        linphone_core_cbs_set_global_state_changed(coreCbs.ptr, &on_global_state_changed_cbs)

        return coreCbs

    def __dealloc__(self):
        print 'Dealloc ' + str(self)
        if self.ptr is not NULL:
            belle_sip_object_data_remove(<belle_sip_object_t *>self.ptr, 'python_user_data')
            linphone_core_cbs_unref(self.ptr)
        self.ptr = NULL

    @property
    def on_global_state_changed_cb(self):
        return self.global_state_cb

    @on_global_state_changed_cb.setter
    def on_global_state_changed_cb(self, cb):
        self.global_state_cb = cb

问题是当我从回调中调用 Core.from_ptr 时,tmpWRef 表示对象已死,因此创建了一个新对象。我在 dealloc 方法中添加了一个打印,我看到该对象还没有被释放。

我的测试程序:

def global_state(lc, state, message):
    print ('External callback : ' + str(state) + ' -> ' + message)

f = Factory.get_instance()
c = f.create_core()
cbs = f.create_core_cbs()
cbs.on_global_state_changed_cb = global_state
c.add_callbacks(cbs)
c.start()

这是我的测试程序的示例输出:

<pylinphone.CoreCallbacks object at 0x7f7211fe6c80>
<weakref at 0x7f7212001368; to 'pylinphone.CoreCallbacks' at 0x7f7211fe6c80>
Internal Callback : 1 : Starting up
<weakref at 0x7f7212001368; dead>
<pylinphone.CoreCallbacks object at 0x7f7212000460>
<weakref at 0x7f7212001368; to 'pylinphone.CoreCallbacks' at 0x7f7212000460>
Dealloc <pylinphone.CoreCallbacks object at 0x7f7212000460>
[...]
Dealloc <pylinphone.CoreCallbacks object at 0x7f7211fe6c80>

【问题讨论】:

  • 请看minimal reproducible example。你的例子应该是最小的。
  • 我实际上删除了大部分代码以直接进入重点......
  • 您在创建wref 后引用计数是否正确?简单地将其转换为 void* 并不能确保它保持活动状态?
  • 我在 python 中找不到任何东西来获取引用或增加弱引用的引用计数...

标签: python c cython wrapper linphone


【解决方案1】:

感谢 DavidW,我发现了问题:weakref 没有被任何人持有。 我在课堂上添加了一个 cpdef wref 字段,现在它可以正常工作了:)

【讨论】:

  • 另一种选择是使用 C API Py_INCREF(当您不再需要它时,由相应的 Py_DECREF 匹配)
  • 我不能这样做,因为我不想干扰现有的 C 库。
  • 你能贴出你最终做了哪些改变的代码吗?
猜你喜欢
  • 1970-01-01
  • 2016-06-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-08-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多