2012-03-05 219 views
4

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

我使用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?
我应该使用完全不同的方法吗?

我打开了在这个问题上有什么建议?

+0

[这篇文章在SWIG邮件列表](http: //article.gmane.org/gmane.comp.programming.swig/5306/match=multi+threading+python)正好说明了这个问题,并要求在SWIG中修复它。我想这个问题自2004年以来一直没有处理过 – Jonathan 2012-03-06 07:09:49

回答

2

如果你痛饮包裹的C++代码调用回调函数的线程,那么很可能没有GIL问题 - 痛饮生成的代码做不执行我见过的任何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++代码。)

+0

我发现如果你使用SWIG导向器,那么如果另一个线程/进程会触发回调,你将需要自己锁定GIL。 – AndyG 2016-10-14 18:39:08