我想知道,如果我打开自己的自定义c代码编译的dll库,就像这样:
import ctypes
my_lib = ctypes.cdll.LoadLibrary('./my_dll.dll')
my_func = my_lib.my_func
# Stuff I want to do with func()
我是否需要在使用后关闭my_lib对象,就像文件对象一样?这样做会使代码更清晰,更有效,更“pythonic”吗?
谢谢!
答案 0 :(得分:8)
通常,您不必释放共享库。考虑到CPython没有提供从内存中卸载常规扩展模块的方法。例如,导入sqlite3将在进程的生命周期中加载_sqlite3扩展和sqlite3共享库。卸载扩展与CPython使用指针作为对象ID的方式不兼容。访问已解除分配(可能重用)的地址将是未定义的行为。
如果您需要卸载或重新加载共享库,并确信它是安全的,则_ctypes扩展模块具有POSIX dlclose
和Windows FreeLibrary
,它们调用相同名称的系统函数。两者都将库句柄作为单个参数。这是_handle
实例的CDLL
属性。如果卸载库失败,则会引发OSError
。
dlclose
和FreeLibrary
都可以通过递减句柄的引用计数来工作。当计数递减到0时,将卸载库。计数最初为1,并且每次为已加载的库调用POSIX dlopen
或Windows LoadLibrary
时,计数都会递增。
POSIX示例
#include <stdio.h>
void __attribute__((constructor)) initialize()
{
printf("initialize\n");
}
void __attribute__((destructor)) finalize()
{
printf("finalize\n");
}
POSIX Python
>>> import ctypes
>>> lib1 = ctypes.CDLL('./lib.so')
initialize
>>> lib2 = ctypes.CDLL('./lib.so')
>>> lib1._handle == lib2._handle
True
>>> import _ctypes
>>> _ctypes.dlclose(lib1._handle)
>>> _ctypes.dlclose(lib1._handle)
finalize
>>> lib1 = ctypes.CDLL('./lib.so')
initialize
>>> _ctypes.dlclose(lib1._handle)
finalize
Windows示例
#include <stdio.h>
#include <windows.h>
void initialize()
{
printf("initialize\n");
}
void finalize()
{
printf("finalize\n");
}
BOOL WINAPI DllMain(HINSTANCE hinstDLL,
DWORD fdwReason,
LPVOID lpReserved)
{
switch(fdwReason)
{
case DLL_PROCESS_ATTACH:
initialize();
break;
case DLL_PROCESS_DETACH:
finalize();
}
return TRUE;
}
Windows Python
>>> import ctypes
>>> lib1 = ctypes.CDLL('./lib.dll')
initialize
>>> lib2 = ctypes.CDLL('./lib.dll')
>>> lib1._handle == lib2._handle
True
>>> import _ctypes
>>> _ctypes.FreeLibrary(lib1._handle)
>>> _ctypes.FreeLibrary(lib1._handle)
finalize
>>> lib1 = ctypes.CDLL('./lib.dll')
initialize
>>> _ctypes.FreeLibrary(lib1._handle)
finalize