【问题标题】:Python calling Cython-function result in core dumpPython 调用 Cython 函数导致核心转储
【发布时间】:2020-07-29 19:59:42
【问题描述】:

我目前正在开发一个需要 Python C-API 的项目
所以我在 C 端创建了一个类,并从它继承了 python 端。
未来的 C 函数之一应返回 None 或 dict。
功能:

static PyObject* handle_data(BaseClassObject* self){
    struct data *data;
    static int counter= 0;

    // get next data from queue
    if ((data= data_queue_pop(self->data_queue))) {
        // TODO: build a Python dict from data and return it
        free_data(data);
        counter++;
    }
    return Py_None;
}

在这个开发阶段,函数data_queue_pop什么都不返回,因此这段代码总是到达return Py_None;
在 Python 方面,我有流动的类:

from concurrent.futures import ThreadPoolExecutor
from threading import Thread
from time import sleep

from utils.logger import getLogger
logger = getLogger(__name__)

try:
    from samplelib import BaseClass
except ImportError:
    from uploadlib import BaseClass


class SomeClass(BaseClass):
    def __init__(self, args):
        super().__init__()
        self.log = logger.getChild(self.__class__.__name__)
        self.version = self.version.rstrip()  # self.version is intilaied in the C side
        self.args = args
        self.wait = True
        self._pool = ThreadPoolExecutor(max_workers=1)
        self.worker = None

    def __enter__(self):
        self.log.info(f"set worker")
        # self.worker = Thread(target=self._handle_data)
        self.worker = self._pool.submit(self._handle_data)
        # self.log.info(f"worker start")
        # self.worker.start()
        self.log.info(f"return self")
        return self

    def __exit__(self, a, b, c):
        self.log.info(f"exit {self.__class__.__name__}")
        # self.log.info('stop thread')
        self.wait = False
        if self.worker:
            self.log.info('wait for thread to stop')
            self.log.info(self.worker.cancel())
            # self.worker.join()
        self.log.info('exiting...')

    def _handle_data(self):
        self.log.info(f"thread started")
        while self.wait:
            data = self.handle_data()
            if data:
                self.log.warning(data)
        self.log.info(f"thread stopped")


def main():
    args = _parse_args()
    with SomeClass(args) as e:
        sleep(2)
        print(e.version)
        # e.wait = False


if __name__ == "__main__":
    main()

不管我尝试做什么,我都会收到以下错误:

Fatal Python error: deallocating None

Current thread 0x00007f8c37b17700 (most recent call first):
  File "/home/ramih/SomeClass-automation/utils/some_module.py", line 50 in _handle_alert
  File "/usr/lib/python3.6/concurrent/futures/thread.py", line 56 in run
  File "/usr/lib/python3.6/concurrent/futures/thread.py", line 69 in _worker
  File "/usr/lib/python3.6/threading.py", line 864 in run
  File "/usr/lib/python3.6/threading.py", line 916 in _bootstrap_inner
  File "/usr/lib/python3.6/threading.py", line 884 in _bootstrap

Thread 0x00007f8c3aedc740 (most recent call first):
  File "./test.py", line 124 in main
  File "./test.py", line 130 in <module>
Aborted (core dumped)

为什么会这样?!
如何调试它?!
我可以让线程更安全吗?!

谢谢。

【问题讨论】:

  • 这是某个地方的引用计数错误 - 您以某种方式设法减少引用 None 的次数比增加它的次数多,这意味着全局 None 对象已被破坏。不幸的是,您的示例与minimal reproducible example 相去甚远,因此很难提供更多细节。
  • @DavidW 也许我的示例远不及最小的可重现示例,但您的回复帮助我找到了解决方案,我只是将return Py_None; 替换为Py_RETURN_NONE;,问题就解决了。两行之间的区别在于宏 Py_RETURN_NONE 还增加了 None 对象的引用,因此,非常感谢 :)
  • 很高兴它有帮助!听起来不错。

标签: python-3.x multithreading python-c-api


【解决方案1】:

感谢@DavidW 的回复,问题已解决,我会分享,以便其他人遇到此问题可以快速找到解决方案。 在这种情况下,您有两种选择:

  • return Py_None; 之前做Py_INCREF(Py_None)
  • 调用宏 Py_RETURN_NONE 已经包含了 ref 增量

【讨论】:

    猜你喜欢
    • 2017-11-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多