<2008年8月>
272829303112
3456789
10111213141516
17181920212223
24252627282930
31123456

统计

  • 随笔 - 44
  • 文章 - 0
  • 评论 - 86
  • 引用 - 0

常用链接

留言簿(6)

随笔分类(31)

随笔档案(44)

Mining

最新随笔

搜索

  •  

最新评论

阅读排行榜

评论排行榜

在 C++ 中使用 Python script

想要在c++ 中嵌入script 代码, 除了自己写脚本引擎外, lua, python 都可以在c++ 中使用, 另外 MonoBind, AngelScript library 都是一些c++ script library, 可以嵌入到c++ 中使用 .
今天在c++ 中试着嵌入 python 代码 (示例代码在 Python-2.5.2\Demo\embed\ 下)

#include <Python.h>
int main(int argc, char *argv[])
{
  
// Py_NoSiteFlag = 1;
  
// Py_SetPythonHome("D:\\usr\\Python"); // PYTHONHOME

  Py_Initialize();
  PyRun_SimpleString(
"from time import time,ctime\n"
                     
"print 'Today is',ctime(time())\n");
  Py_Finalize();
  
return 0;
}

在运行时可能会产生类似 'import site' failed; use -v for traceback 的错误, 原因是python 在import module 的时候的路径问题. 有3种方法可以解决(以前通过设置环境变量 PYTHONPATH 好像在2.5 已经无效了).
0. 取消注释 Py_NoSiteFlag = 1;
这个只是取消import site , 当然如果在代码中要import 啥的话, 还是会出现错误的.
a. 设置环境变量 PYTHONHOME = D:\usr\Python 
b. 在调用 Py_Initialize 之前调用函数
Py_SetPythonHome("D:\\usr\\Python");  // 参数是python 的安装目录

2. 其他一些有用的资源
Python/C API Reference Manual (API 参考) ,  Extending and Embedding the Python Interpreter (扩展及嵌入Python解释器, 主要说明了如何扩展Python, 给Python 写扩展, 其中 5. Embedding Python in Another Application  一章讲述了在C++中嵌入/调用Python 代码 )

使用C/C++扩展Python  对文 Extending and Embedding the Python Interpreter 作了精简, 很不错的一篇文章, 但是跳过了一些基础 .

Building Hybrid Systems with Boost.Python 介绍了使用boost.python 方便python 插件开发, python绑定c++程序 是其中文版本.

Embedding Python in Multi-Threaded C/C++ Applications 讲了c++在多线程环境如何使用Python , 文 C++多线程中调用python api函数 提供了一个多线程的封装.

SCXX - A Simple Python/C++ API
http://davidf.sjsoft.com/mirrors/mcmillan-inc/scxx.html

C++扩展和嵌入Python应用 (介绍了一些Python/C API 函数, 以及ext 例子, 一般般)
http://hi.baidu.com/yunsweet/blog/item/20b08aeebaa2b1282cf534c7.html


3. Python 多线程的使用

zz http://blog.csdn.net/liguangyi/archive/2007/06/20/1659697.aspx 
今天看了近一天关于多线程的应用中,如何安全调用python方面的资料,开始的时候看的简直头大如斗,被python语言的全局锁(Global Interpreter Lock)、线程状态(Thread State )等都有点绕晕了,后来经过各方面文章和帮助文档的相互参考,发现对于2.4/2.5版本,提供了PyGILState_Ensure, PyGILState_Release,哎,这下可方便大发了。

一、首先定义一个封装类,主要是保证PyGILState_Ensure, PyGILState_Release配对使用,而且这个类是可以嵌套使用的。

#include <python.h>

class PyThreadStateLock
{
public:
    PyThreadStateLock(void)
    {
        state = PyGILState_Ensure( );
    }

    ~PyThreadStateLock(void)
    {
         PyGILState_Release( state );
    }
private:
    PyGILState_STATE state;
};


二、在主线程中,这样处理

    // 初始化
    Py_Initialize();
    // 初始化线程支持
    PyEval_InitThreads();
    // 启动子线程前执行,为了释放PyEval_InitThreads获得的全局锁,否则子线程可能无法获取到全局锁。
    PyEval_ReleaseThread(PyThreadState_Get());
  
    // 其他的处理,如启动子线程等
    ......
      
    // 保证子线程调用都结束后
    PyGILState_Ensure();
    Py_Finalize();
    // 之后不能再调用任何python的API

三、在主线程,或者子线程中,调用python本身函数的都采用如下处理

    {
        class PyThreadStateLock PyThreadLock;
        // 调用python的API函数处理
        ......
    }

呵呵,看这样是否非常简单了。


另外还有两个和全局锁有关的宏,Py_BEGIN_ALLOW_THREADS 和 Py_END_ALLOW_THREADS。这两个宏是为了在较长时间的C函数调用前,临时释放全局锁,完成后重新获取全局锁,以避免阻塞其他python的线程继续运行。这两个宏可以这样调用

    {
        class PyThreadStateLock PyThreadLock;
        // 调用python的API函数处理
        ......

        Py_BEGIN_ALLOW_THREADS
        // 调用需要长时间的C函数
        ......
        Py_END_ALLOW_THREADS

        // 调用python的API函数处理
        ......
    }

4. 可能的错误及解决
a. 在vs 200x 下 debug 模式出现链接问题
extmodule.obj : error LNK2019: unresolved external symbol __imp___Py_Dealloc referenced in function _PySwigObject_format
extmodule.obj : error LNK2019: unresolved external symbol __imp___Py_NegativeRefcount referenced in function _PySwigObject_format
extmodule.obj : error LNK2001: unresolved external symbol __imp___Py_RefTotal
extmodule.obj : error LNK2019: unresolved external symbol __imp___PyObject_DebugFree referenced in function _PySwigObject_dealloc
extmodule.obj : error LNK2019: unresolved external symbol __imp___PyObject_DebugMalloc referenced in function _PySwigObject_New
extmodule.obj : error LNK2019: unresolved external symbol __imp__Py_InitModule4TraceRefs referenced in function _init_extmodule

主要是因为 Py_DEBUG/Py_TRACE_REFS 引起, 修改 Python\include 下的 pyconfig.h, object.h 两个文件就行了 ... 详见 http://www.nabble.com/link-error-in-debug-mode-td3126668.html 

posted on 2008-08-14 17:55 泡泡牛 阅读(10276) 评论(4)  编辑 收藏 引用 所属分类: Python

评论

# re: 在 C++ 中使用 Python script  2008-08-15 20:34 泡泡牛

谁知道有什么其他的可以在c++ 里面调用的script 引擎吗?
  回复  更多评论    

# re: 在 C++ 中使用 Python script  2008-09-24 20:10 sheena

主要是因为 Py_DEBUG/Py_TRACE_REFS 引起, 修改 Python\include 下的 pyconfig.h, object.h 两个文件就行了 ... 详见 http://www.nabble.com/link-error-in-debug-mode-td3126668.html
这个解释我还是没有看明白,?您能再解释下吗
  回复  更多评论    

# re: 在 C++ 中使用 Python script  2008-09-24 22:17 泡泡牛

1. 修改 pyconfig.h

修改

#ifdef _DEBUG
# define Py_DEBUG
#endif



#ifdef _DEBUG
//# define Py_DEBUG
#endif

修改

# ifdef _DEBUG
# pragma comment(lib,"python24_d.lib")
# else
# pragma comment(lib,"python24.lib")
# endif /* _DEBUG */



# ifdef _DEBUG
# pragma comment(lib,"python24.lib")
# else
# pragma comment(lib,"python24.lib")
# endif /* _DEBUG */


2. object.h
修改
#if defined(Py_DEBUG) && !defined(Py_TRACE_REFS)
#define Py_TRACE_REFS
#endif



#if defined(Py_DEBUG) && !defined(Py_TRACE_REFS)
// #define Py_TRACE_REFS
#endif
  回复  更多评论    

# re: 在 C++ 中使用 Python script  2015-04-11 11:02 布布

@泡泡牛
牛逼!!!
  回复  更多评论    

只有注册用户登录后才能发表评论。
【推荐】超50万行VC++源码: 大型组态工控、电力仿真CAD与GIS源码库
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理