嵌入式 Python 应用程序中 Py_Finalize 期间发生致命错误

2024-03-18

感谢您的帮助——这个问题的变体已经被问过很多次,但我还没有找到完整的答案。我正在使用 MS MFC 类将嵌入式 Python 3.4.2 添加到用 C++ 编写的现有模拟器工具中。该应用程序是多线程的,以便用户可以执行Python脚本并与模拟器系统交互。

怎样才能成功退出呢? 我是否以正确的顺序使用 GIL 和线程状态命令? 我是否提前结束了Python解释器线程并破坏了Python线程合并机制?

我的问题是,当我调用 Py_Finalize 时,它​​调用 wait_for_thread_shutdown,然后调用 PyThreadState_Get,并遇到致命错误“PyThreadState_Get:没有当前线程”。根据检测到致命错误的点,它似乎与多线程嵌入式 Python 应用程序末尾的线程合并有关。

我已经浓缩了我的代码以使其更加清晰并消除了任何看起来不相关的内容。如果我走得太远或不够远,我深表歉意。主线程初始化并完成Python。

BOOL CSimApp::InitInstance()
{
    ...
    // Initialize command table for appl. object and for documents
    int iReturn = PyImport_AppendInittab("sim", &PyInit_SimApp);
    iReturn = PyImport_AppendInittab("sim_doc", &PyInit_SimDoc);

    // Initialize Python and prepar to create threads
    _pHInstance = new CPyInstance();
    ...
}

int CSimApp::ExitInstance() 
{
    ...
    if (_pHInstance) {
        delete _pHInstance;
        _pHInstance = NULL;
    }
    ...
}

我使用实用程序类来创建 Python 实例 (CPyInstance) 并管理 Python GIL (ACQUIRE_PY_GIL)。当应用程序初始化时,还会创建 CPyInstance 的实例。 CPyInstance 类初始化并完成 Python 线程管理。 Python 全局锁管理是通过 ACQUIRE_PY_GIL 和 RELEASE_PY_GIL 结构完成的。

class CPyInstance
{
public:
    CPyInstance();
    ~CPyInstance();
    static PyThreadState * mainThreadState;
};

inline CPyInstance::CPyInstance()
{
    mainThreadState = NULL;
    Py_Initialize();
    PyEval_InitThreads();
    mainThreadState = PyThreadState_Get();
    PyEval_ReleaseLock();
}

inline CPyInstance::~CPyInstance()
{
    Py_Finalize();
}

static CPyInstance    *_pHInstance = NULL;

int PyExit()
{
    if (_pHInstance) {
        delete _pHInstance;
        _pHInstance = NULL;
    }
    return 0;
}

struct ACQUIRE_PY_GIL {
    PyGILState_STATE state;
    ACQUIRE_PY_GIL() { state = PyGILState_Ensure(); }
    ~ACQUIRE_PY_GIL() { PyGILState_Release(state); }
};

struct RELEASE_PY_GIL {
    PyThreadState *state;
    RELEASE_PY_GIL() {  state = PyEval_SaveThread(); }
    ~RELEASE_PY_GIL() { PyEval_RestoreThread(state); }
};

Python 解释器线程是为了响应 CMainFrame 窗口处理的 Windows 消息而创建的。 Python 线程和解释器响应用户命令而运行。当用户完成解释器 (Control-Z) 时,解释器退出,线程清除并删除 Python 线程状态,然后线程自行终止。

void CMainFrame::OnOpenPythonInterpreter()
{
    // Create PyThread thread
    m_pPyThread = (CPyThread*)AfxBeginThread(RUNTIME_CLASS(CPyThread),
                    THREAD_PRIORITY_BELOW_NORMAL,0, CREATE_SUSPENDED);
    CMainFrame* mf = (CMainFrame*)theApp.m_pMainWnd;
    m_pPyThread->SetOwner(this,((CWnd*)mf)->GetSafeHwnd());
    m_pPyThread->CreateLocks(&m_PyThreadEvent,&m_PyThreadBusyMutex);
    m_pPyThread->ResumeThread();
}

CPyThread类实际上调用了Python解释器。当解释器返回时,GIL 被释放,Python 线程状态被清除和删除。线程响应 PostQuitMessage 而终止。

int CPyThread::Run() 
{
    PyEval_AcquireLock();
    PyInterpreterState * mainInterpreterState = CPyInstance::mainThreadState->interp;
    PyThreadState * myThreadState = PyThreadState_New(mainInterpreterState);
    PyEval_ReleaseLock();

    try {
        ACQUIRE_PY_GIL    lock;
        FILE* fp1 = stdin;
        char *filename = "Embedded";
        PyRun_InteractiveLoop(fp1, filename);
    } catch(const std::exception &e) {
        safe_cout << "Exception in PyRun_InteractiveLoop: " << e.what() << "\n";
    } catch(...) {
        std::cout << "Exception in Python code: UNKNOWN\n";
    }

    PyThreadState_Clear(myThreadState);
    PyThreadState_Delete(myThreadState);

    ::PostQuitMessage(0);
    return 0;
}

int CPyThread::ExitInstance() 
{
    return CWinThread::ExitInstance();
}

根据“user4815162342”的建议,我修改了 ~CPyInstance() 析构函数以在调用 Py_Finalize() 之前获取 GIL。现在我的应用程序似乎可以正常退出,谢谢。

inline CPyInstance::~CPyInstance()
{
    try {
        PyGILState_STATE state = PyGILState_Ensure();
        Py_Finalize();
    } catch(const std::exception &e) {
        safe_cout << "Exception in ~CPyInstance(): " << e.what() << "\n";
    } catch(...) {
        std::cout << "Exception in Python code: UNKNOWN\n";
    }
}

你正在呼唤Py_Finalize无需持有全局解释器锁。这是不允许的:必须为每个 Python API 调用持有锁,获取 GIL 本身的调用除外。

The ACQUIRE_PY_GILRAII 防护对于此目的没有用,因为它会在之后尝试释放 GILPy_Finalize返回 - 在这种情况下,您必须调用PyGILState_Ensure没有匹配的版本。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

嵌入式 Python 应用程序中 Py_Finalize 期间发生致命错误 的相关文章

  • 使用 OpenPyXL 迭代工作表和单元格,并使用包含的字符串更新单元格[重复]

    这个问题在这里已经有答案了 我想使用 OpenPyXL 来搜索工作簿 但我遇到了一些问题 希望有人可以帮助解决 以下是一些障碍 待办事项 我的工作表和单元格数量未知 我想搜索工作簿并将工作表名称放入数组中 我想循环遍历每个数组项并搜索包含特
  • 如何将 numpy.matrix 提高到非整数幂?

    The 运算符为numpy matrix不支持非整数幂 gt gt gt m matrix 1 0 0 5 0 5 gt gt gt m 2 5 TypeError exponent must be an integer 我想要的是 oct
  • 在 Unity 中实现 Fur with Shells 技术

    我正在尝试在 Unity 中实现皮毛贝壳技术 http developer download nvidia com SDK 10 5 direct3d Source Fur doc FurShellsAndFins pdf Fins 技术被
  • ExpectedFailure 被计为错误而不是通过

    我在用着expectedFailure因为有一个我想记录的错误 我现在无法修复 但想将来再回来解决 我的理解expectedFailure是它会将测试计为通过 但在摘要中表示预期失败的数量为 x 类似于它如何处理跳过的 tets 但是 当我
  • Python - 按月对日期进行分组

    这是一个简单的问题 起初我认为很简单而忽略了它 一个小时过去了 我不太确定 所以 我有一个Python列表datetime对象 我想用图表来表示它们 x 值是年份和月份 y 值是此列表中本月发生的日期对象的数量 也许一个例子可以更好地证明这
  • C# xml序列化必填字段

    我需要将一些字段标记为需要写入 XML 文件 但没有成功 我有一个包含约 30 个属性的配置类 这就是为什么我不能像这样封装所有属性 public string SomeProp get return someProp set if som
  • Python 3 中“map”类型的对象没有 len()

    我在使用 Python 3 时遇到问题 我得到了 Python 2 7 代码 目前我正在尝试更新它 我收到错误 类型错误 map 类型的对象没有 len 在这部分 str len seed candidates 在我像这样初始化它之前 se
  • 从 pygame 获取 numpy 数组

    我想通过 python 访问我的网络摄像头 不幸的是 由于网络摄像头的原因 openCV 无法工作 Pygame camera 使用以下代码就像魅力一样 from pygame import camera display camera in
  • 空指针与 int 等价

    Bjarne 在 C 编程语言 中写道 空指针与整数零不同 但 0 可以用作空指针的指针初始值设定项 这是否意味着 void voidPointer 0 int zero 0 int castPointer reinterpret cast
  • 如何在 Django 中使用并发进程记录到单个文件而不使用独占锁

    给定一个在多个服务器上同时执行的 Django 应用程序 该应用程序如何记录到单个共享日志文件 在网络共享中 而不保持该文件以独占模式永久打开 当您想要利用日志流时 这种情况适用于 Windows Azure 网站上托管的 Django 应
  • C 函数 time() 如何处理秒的小数部分?

    The time 函数将返回自 1970 年以来的秒数 我想知道它如何对返回的秒数进行舍入 例如 对于100 4s 它会返回100还是101 有明确的定义吗 ISO C标准没有说太多 它只说time 回报 该实现对当前日历时间的最佳近似 结
  • 编译时展开 for 循环内的模板参数?

    维基百科 here http en wikipedia org wiki Template metaprogramming Compile time code optimization 给出了 for 循环的编译时展开 我想知道我们是否可以
  • 相当于Linux中的导入库

    在 Windows C 中 当您想要链接 DLL 时 您必须提供导入库 但是在 GNU 构建系统中 当您想要链接 so 文件 相当于 dll 时 您就不需要链接 为什么是这样 是否有等效的 Windows 导入库 注意 我不会谈论在 Win
  • 从 Python 中的类元信息对 __init__ 函数进行类型提示

    我想做的是复制什么SQLAlchemy确实 以其DeclarativeMeta班级 有了这段代码 from sqlalchemy import Column Integer String from sqlalchemy ext declar
  • 如何使用google colab在jupyter笔记本中显示GIF?

    我正在使用 google colab 想嵌入一个 gif 有谁知道如何做到这一点 我正在使用下面的代码 它并没有在笔记本中为 gif 制作动画 我希望笔记本是交互式的 这样人们就可以看到代码的动画效果 而无需运行它 我发现很多方法在 Goo
  • 在 Python 类中动态定义实例字段

    我是 Python 新手 主要从事 Java 编程 我目前正在思考Python中的类是如何实例化的 我明白那个 init 就像Java中的构造函数 然而 有时 python 类没有 init 方法 在这种情况下我假设有一个默认构造函数 就像
  • 为什么 std::uint32_t 与 uint32_t 不同?

    我对 C 有点陌生 我有一个编码作业 很多文件已经完成 但我注意到 VS2012 似乎有以下语句的问题 typedef std uint32 t identifier 不过 似乎将其更改为 typedef uint32 t identifi
  • C# 使用“?” if else 语句设置值这叫什么

    嘿 我刚刚看到以下声明 return name null name NA 我只是想知道这在 NET 中叫什么 是吗 代表即然后执行此操作 这是一个俗称的 条件运算符 三元运算符 http en wikipedia org wiki Tern
  • Python:元类属性有时会覆盖类属性?

    下面代码的结果让我感到困惑 class MyClass type property def a self return 1 class MyObject object metaclass MyClass a 2 print MyObject
  • 指针和内存范围

    我已经用 C 语言编程有一段时间了 但对 C 语言还是很陌生 有时我对 C 处理内存的方式感到困惑 考虑以下有效的 C 代码片段 const char string void where is this pointer variable l

随机推荐

  • 我如何在学说上使用“外键”?

    我正在 symfony2 和原则上制作课程管理系统 我对在学说中使用外键感到困惑 实体 用户 php class User extends BaseUser ORM Id ORM Column type integer ORM Genera
  • 是否可以通过 smtp 通过 bash 脚本发送邮件?

    我有postfix dovecot 我想制作可以使用 SMTP 的 bash 脚本 我不想使用sendmail 是否可以 也许有人有一些代码示例 男孩 当挑战被抛出时 它总是bash就在我的头顶上 bin sh function check
  • 是否需要锁定对 bool 的访问,或者是否过度杀伤力

    我有一个主要设计为 POCO 类的类 具有各种线程和任务可以读取其值 只有其他人偶尔会更新这些值 这似乎是 ReaderWriterLockSlim 的理想场景 问题是 在类中 如果需要线程安全的属性 如果该属性是bool 是不是有点大材小
  • 窗口上的代理

    我想设立一个Proxy当定义了新属性时它会警告我window目的 实际上我想捕获所有全局变量声明 let handler defineProperty target key descriptor console log hey key re
  • 如何在 w3m 终端中使用 Javascript?

    我发现文本浏览器 w3m 在我看来是迄今为止最好的 然而 主要问题是Javascript 当我使用 Stackoverflow 时 我根本看不到评论 我不确定让 Javascript 在终端中存在什么限制 如何为终端启用至少部分 JavaS
  • 在 pthread 中实现 FIFO 互斥体

    我正在尝试实现支持并发插入的二叉树 甚至可能在节点之间发生 但不必为每个节点分配全局锁或单独的互斥体 相反 分配的此类锁的数量应按线程数量使用树 因此 我最终得到了一种锁车队 http en wikipedia org wiki Lock
  • 在 R 中查找特殊字符的第三次出现并删除之前的所有内容

    我有这个包含 URL 的示例向量 我的目标是获取URL的路径 sample1 lt c http tercihblog com indirisu docugard http funerariagomez com js ggogle a201
  • SQL 查询选择每组具有最大值的每一行

    我对 SQL 很陌生 这个问题让我难住了 你能帮我解答这个问题吗 我有以下 2 个表 表 1 问题表 Id RunId Value 1 1 10 2 1 20 3 1 30 4 2 40 5 2 50 6 3 60 7 4 70 8 5 8
  • 如何将sql查询结果转储到文件中

    好吧 我现在的情况是 我需要将 sql 查询的结果转储到文件中 这是出于备份目的 我尝试从终端运行以下命令 mysql e select from products where brand id 5 u root p database na
  • WTSRegisterSessionNotification 有时在 XP home 启动时不起作用

    我正在使用该函数 消息来检查工作站是否已锁定 现在我的应用程序位于启动文件夹中 它在 XP pro 上运行没有任何问题 但由于我在 XP home 上使用该程序 WTSRegisterSessionNotification 在启动时大约有
  • 一起使用facet_grid和facet_wrap

    我正在尝试使用创建图表facet wrap with a facet grid在每个包裹的方面内 但我无法做到 有什么建议么 例如 如果我要对 2 个数量的月平均值进行同比比较 我希望 2 个面 每个数量一个 每个月份的 5 个数量方面都有
  • Flash 源代码控制 - 最佳实践

    我现在正在开发一个 Flash 项目 我不得不迫使设计人员使用我们的源代码控制存储库 SVN 来帮助管理和跟踪项目 让他完全接受源代码控制的好处是一场艰苦的战斗 但它正在到来 除了我是唯一一个参与 Flash 项目的项目之外 我以前从未在
  • 无法创建目录 /home/hadoop/hadoopinfra/hdfs/namenode/current

    我收到错误 Cannot create directory home hadoop hadoopinfra hdfs namenode current 尝试在我的本地 Mac 上安装 hadoop 时 这可能是什么原因 仅供参考 我将我的
  • 更新嵌套字典中的值 - Python

    我创建了一个字典 如下所示 gP dict fromkeys range 6 a None b None c None d None 现在 当我尝试修改一个值时 gP 0 a 1 由于某种原因 所有的值a 不管它们属于哪个键 更改为1 如下
  • 为什么我的 UDP 广播失败?

    我正在尝试发送 UDP 广播 但wireshark 没有报告任何流量 这是执行发送的代码片段 void SendBroadcast String ip 255 255 255 255 int port 30718 String messag
  • 在 shell 脚本中扩展变量

    我有一个需要循环的查询 query select dbserver as server while read dbserver username password dbname type do mysql h dbserver u user
  • 如何使用 VBA 将数据从关闭的工作簿(保持关闭状态)复制到主工作簿中?

    我需要使用 VBA 将数据从关闭的工作簿复制到主工作簿中 而不打开它们 I use Workbooks Open从 4 6 个文件开始 每个需要打开的文件都会大大减慢复制操作的速度 我需要高效的 VBA 代码来复制数据 而无需打开每个文件
  • Azure 存储非经典 (V2) - 如何配置自定义域

    在新的 Azure 门户中 有 2 个存储帐户 非经典帐户和经典帐户 因为我认为经典就是旧版本 所以我选择非经典 问题是 我无法在新门户上配置自定义域 它将我重定向到旧的 azure 门户 manage windowszuare com 问
  • 隐藏包中的模块导入

    我有一个小包 有一些依赖项 例如 pandas 和 gensim 文件结构是这样的 package init py agg clean py In the init py文件 我有import agg clean所以我能够以链式方式访问这些
  • 嵌入式 Python 应用程序中 Py_Finalize 期间发生致命错误

    感谢您的帮助 这个问题的变体已经被问过很多次 但我还没有找到完整的答案 我正在使用 MS MFC 类将嵌入式 Python 3 4 2 添加到用 C 编写的现有模拟器工具中 该应用程序是多线程的 以便用户可以执行Python脚本并与模拟器系