SWIG C++ Python 多态性和多线程

Posted

技术标签:

【中文标题】SWIG C++ Python 多态性和多线程【英文标题】:SWIG C++ Python polymorphism and multi-threading 【发布时间】:2012-03-05 15:35:41 【问题描述】:

我正在使用SWIG 将第 3 方 C++ 包集成到 python 应用程序。该软件包通过网络连接到专有 API 并接收更新。总体流程是python实例化一个C++对象,调用它的函数来设置它,然后等待更新。

我使用SWIG's directors feature 为更新实现了回调机制,并且在从 python 或从 python 调用的 C++ 函数进行测试时,它运行良好。也就是说,我可以在 Python 中继承一个 C++ 类,从 C++ 调用它的虚函数,然后查看 python 代码优先执行。

问题: 当我收到来自网络的更新时,我得到:

The thread 'Win32 Thread' (0x1f78) has exited with code 0 (0x0).
Unhandled exception at 0x1e0650cb in python.exe: 0xC0000005: Access violation writing location 0x0000000c.

在调用回调函数时从python27.dll 中抛出此异常。我的怀疑是: 我违反了GIL AFAIU 更新来自不同的线程并使用该线程调用 python 的代码。

在这一点上,我不知所措。 SWIG 的导向器功能是否仅限于在 python 中启动的流(即从 python 托管线程)? 我该如何规避这个?如何诱导从 C++ 到 python 的更新?甚至可以使用 SWIG 吗? 我应该使用完全不同的方法吗?

我愿意就此事提出任何建议...

【问题讨论】:

This post on SWIG mailing list 准确地谈论了这个问题,并呼吁采取行动在 SWIG 中修复它。我想这自 2004 年以来就没有处理过 您可以将-thread 传递给swig,它会在您的python 回调被调用时生成代码来获取GIL(即通过swig 的director 功能进行的回调)。这里有一个关于这个话题的很好的讨论:github.com/swig/swig/issues/927#issuecomment-289279243 【参考方案1】:

如果您的 SWIG 包装的 C++ 代码在线程内调用回调例程,那么可能不存在 GIL 问题 - SWIG 生成的代码不执行我见过的任何 GIL 管理,这意味着当 Python 代码调用在您的 C++ 代码中,您将在整个调用过程中保留 GIL。

但是,如果您的 C++ 代码将回调推迟到另一个线程,那么您很可能违反了 GIL。这很容易解决:在调用回调之前,调用 PyGILState_Ensure(),当回调完成时,调用 PyGILState_Release。请参阅http://docs.python.org/c-api/init.html,“非 Python 创建的线程”部分。 (如果您在此处使用 C++ 异常处理,则可能需要格外小心以确保您可以释放 GIL。)

如果您还没有查看堆栈跟踪,则值得验证 NULL 指针 deref 不是在您的代码中发生的愚蠢的事情。 (您可以使用 VS/GDB/WinDBG 附加到运行您的代码的 Python 进程;Python 执行将仍然难以理解,但您可以通过这种方式跟踪您的 C++ 代码。)

【讨论】:

我发现如果您使用的是 SWIG 导向器,那么如果另一个线程/进程将触发回调,您将需要自己锁定 GIL。

以上是关于SWIG C++ Python 多态性和多线程的主要内容,如果未能解决你的问题,请参考以下文章

SWIG:将异常从 Python 抛出到 C++

使用 SWIG 跨 C++ 和 Ruby 的多态性

如何多线程(多进程)加速while循环(语言-python)?

单线程多线程和多进程的效率对比实验

什么是多线程,多进程?

带有回调的 SWIG C++ 绑定