我目前正在使用pybind11来生成cpp-python接口.我有一个回调函数,如下

Pyind_回调.h

#pragma once


#include <stdint.h>

#include <functional>

#include <pybind11/pybind11.h>
#include <pybind11/stl.h>
#include <pybind11/functional.h>

namespace py = pybind11;

typedef std::function<void(uint32_t, uint32_t)> tCbType;

void pybind_add_cb(tCbType func);

Pyind_allback.cpp

#include "Pyind_回调.h"
#include <vector>

static std::vector<tCbType> cb_func{};

void pybind_add_cb(tCbType func)
{
    cb_func.push_back(func);
}

我的pybind11绑定实现如下

Main.cpp

#include <pybind11/pybind11.h>

#include "Pyind_回调.h"

namespace py = pybind11;


PYBIND11_MODULE(pybind_interface, m) {
    m.def("pybind_add_cb",            &pybind_add_cb,            "");
}

生成的文件是pyind_allback.so,我将其导入以供在我的python单元测试中使用,如下所示

Test.py

import unittest

from pybind_interface import *

class TestPyBind11(unittest.TestCase):
    def setUp(self):
        self.cb_count = 0
        print("Starting test!")
    
    def cb_func(self, start, end):
        print(f"cb_func(start=0x{start:08x}, end=0x{end:08x})")
        self.cb_count += 1
    
    def test_callback(self):
        pybind_add_cb(lambda start,end: self.cb_func(start, end))
#=================================================================
if __name__ == '__main__':
    unittest.main()

尽管测试成功运行并在测试通过后返回"OK",但在unittest框架的main.py中的sys.exit(not self.result.wasSuccessful())行中停留了一段时间.我已经验证了self.result.wasSuccessful()返回1,并且它应该得到一个sys.exit(0),然后它应该优雅地退出.但这并没有发生.我得到的结果如下

Starting test!
.
----------------------------------------------------------------------
Ran 1 test in 0.000s

OK
*stuck at this point*

但在上面的情况下,Python从未退出,并停留在调用sys.exit(0)的时候.如果我在unittest函数中强制将sys.exit(0)更改为os._exit(0),则它将正确退出.这是我的全部代码.这个实现可以通过swg实现,但我不想使用它,因为语法很难.

有人知道为什么会发生这种事吗?

我希望unittest在遇到sys.exit(0)时正常退出.但即使测试通过,

推荐答案

Very related question,可能是重复的,然而,当我在我的机器上运行你的代码(不同的优化级别,使用/不使用valrgind)时,它看起来像是双重释放的问题,因此是未定义的行为,而不是简单的python解释器死机.

显然,在解释器终止时,Python正试图"删除"先前传递给pybind_add_cb的lambda对象.这发生在cb_func销毁过程中它已经在C++端被删除之后.要解决此问题,您可以提供清理功能,如引号中的答案所示:

  m.def("pybind_add_cb", &pybind_add_cb, "");
  m.add_object("_cleanup", py::capsule([]{ cleanup(); }));

它可以像这样简单

void cleanup() {
    std::cout << "cleanup()\n";
    cb_func.clear();
}

Python-3.x相关问答推荐

如何创建一个polars gramme,给出列表中的列名,

如何有效地计算Kernel/Matrix

如何从拼图分区数据集中读取数据到Polar

Python根据阈值对数字进行分组

如果行在所有上级索引中都为0,如何删除下级索引行?

根据另一列中的条件填写该列中的值

如何从包含SPAN文本的标记中获取链接

无法使用xpath关闭selenium中的弹出窗口

在 sum() 中将字符串转换为 int (或 float)

从 https://www.niftytrader.in/stock-options-chart/sbin 提取 SBIN 股票最大痛苦值的 Python 代码不起作用 - 我错过了什么?

安装没有 sudo 权限的 python3 和 pip3

在 pytest 中,如何测试 sys.exit('some error message')?

如何向 scikit-learn 函数添加类型提示?

如何在 django 中没有循环的情况下获得前键的前键?

python 3中的SQLAlchemy ER图

TypeError:JSON 对象必须是 str,而不是 'dict'

multiprocessing.Queue 中的 ctx 参数

创建日志(log)文件

将字符串拆分为最大长度 X 的片段 - 仅在空格处拆分

Django 教程 unicode 不起作用