ctypes 是 Python 的外部函数库。它提供了与 C 兼容的数据类型,并允许调用 DLL 或共享库中的函数。可使用该模块以纯 Python 形式对这些库进行封装。
Hello World
编写C文件
编译C文件
编写Python文件、测试
1. 编写C文件 1 2 3 4 5 6 7 #include <stdio.h> int hello (const char * name) { printf ("~~~hello %s ! \n" , name); return 0 ; }
2. 编译C文件 不同平台生成不同格式的动态库,windows下为dll,linux下为so
gcc -fPIC -shared hello_module.c -o hello_module.dylib
3. 编写Python文件 1 2 3 4 5 6 import ctypesfrom ctypes import c_char_plib = ctypes.cdll.LoadLibrary("hello_module.dylib" ) lib.hello(c_char_p(bytes ("world" , "utf-8" )))
类型映射关系
ctypes
C 类型
Python类型
c_bool
_Bool
bool (1)
c_char
char
单字符字节对象
c_wchar
wchar_t
单字符字符串
c_byte
char
int
c_ubyte
unsigned char
int
c_short
short
int
c_ushort
unsigned short
int
c_int
int
int
c_uint
unsigned int
int
c_long
long
int
c_ulong
unsigned long
int
c_longlong
__int64 或 long long
int
c_ulonglong
unsigned __int64 或 unsigned long long
int
c_size_t
size_t
int
c_ssize_t
ssize_t 或 Py_ssize_t
int
c_float
float
float
c_double
double
float
c_longdouble
long double
float
c_char_p
char * (NUL terminated)
字节串对象或 None
c_wchar_p
wchar_t * (NUL terminated)
字符串或 None
c_void_p
void *
int 或 None
回调函数 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 ############## main.c ############## #include <stdint.h> #include <stdio.h> struct mes_t { uint32_t field1; uint32_t field2; void * data; }; typedef int function_callback (struct mes_t * message ) ;function_callback* my_callback; int function_one (function_callback fcb) { my_callback = fcb; struct mes_t mes ; mes.field1 = 132 ; mes.field2 = 264 ; mes.data = NULL ; printf ("Got from python: %d\n" , my_callback( &mes ) ); }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 import ctypestestlib = ctypes.CDLL('./testlib.so' ) class mes_t (ctypes.Structure): _fields_ = ( ('field1' , ctypes.c_uint32), ('field2' , ctypes.c_uint32), ('data' , ctypes.c_void_p)) callback_type = ctypes.CFUNCTYPE(ctypes.c_int, ctypes.POINTER(mes_t) ) def the_callback (mes_p ): my_mes = mes_p[0 ] print "I got a mes_t object! mes.field1=%r, mes.field2=%r, mes.data=%r" \ % (my_mes.field1, my_mes.field2, my_mes.data) return 999 result = testlib.function_one(callback_type(the_callback) ) gcc -shared -o testlib.so -fPIC main.c python main.py
参考:http://blog.sina.com.cn/s/blog_6e22d8fb0102y462.html
线程状态和GIL Python解释器不是完全线程安全的。为了支持多线程Python程序,有一个全局锁,称为global interpreter lock或GIL,它必须由当前线程持有才能安全访问Python对象。没有锁,即使最简单的操作也可能导致多线程程序中的问题:例如,当两个线程同时增加同一对象的引用计数时,引用计数可能最终只增加一次而不是两次。
释放GIL 1 2 3 Py_BEGIN_ALLOW_THREADS ... Do some blocking I/O operation ... Py_END_ALLOW_THREADS
非Python创建的线程 当使用专用的Python API(例如threading模块)创建线程时,线程状态会自动关联到它们,因此上面显示的代码是正确的。但是,当从C创建线程时(例如由具有自己的线程管理的第三方库),它们不持有GIL,也没有线程状态结构。
如果你需要从这些线程调用Python代码(通常这将是上述第三方库提供的回调API的一部分),你必须首先通过创建线程状态数据结构来注册这些线程和解释器,然后获取GIL,最后存储他们的线程状态指针,然后才能开始使用Python / C API。当你完成后,你应该重置线程状态指针,释放GIL,最后释放线程状态数据结构。
1 2 3 4 5 6 7 8 9 PyGILState_STATE gstate; gstate = PyGILState_Ensure(); /* Perform Python actions here. */ result = CallSomeFunction(); /* evaluate result or handle exception */ /* Release the thread. No Python API allowed beyond this point. */ PyGILState_Release(gstate);
释放GIL和非python创建的线程中调用python函数都没有测试成功…
参考