释放Python中打开的ctypes库

Yux*_*ang 5 python dll ctypes

我想知道,如果我打开自己的自定义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()
Run Code Online (Sandbox Code Playgroud)

我需要在使用后关闭my_lib对象,就像文件对象一样吗?这样做会使代码更清晰,更高效,更"pythonic"吗?

谢谢!

Ery*_*Sun 9

通常,您不必释放共享库.考虑到CPython没有提供从内存中卸载常规扩展模块的方法.例如,导入sqlite3将在进程的生命周期中加载_sqlite3扩展和sqlite3共享库.卸载扩展与CPython使用指针作为对象ID的方式不兼容.访问已解除分配(可能重用)的地址将是未定义的行为.

如果您需要卸载或重新加载共享库,并确信它是安全的,则_ctypes扩展模块具有POSIX dlclose和Windows FreeLibrary,它们调用同名的系统函数.两者都将库句柄作为单个参数.这是实例的_handle属性CDLL.如果卸载库失败,OSError则引发.

双方dlcloseFreeLibrary通过减小手柄的引用计数工作.当计数递减到0时,库将被卸载.计数最初为1,并且每次为已加载的库调用POSIX dlopen或Windows 时,计数都会递增LoadLibrary.

POSIX示例

#include <stdio.h>

void __attribute__((constructor)) initialize()
{
    printf("initialize\n");
}

void __attribute__((destructor)) finalize()
{
    printf("finalize\n");
}
Run Code Online (Sandbox Code Playgroud)

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
Run Code Online (Sandbox Code Playgroud)

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;
}
Run Code Online (Sandbox Code Playgroud)

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
Run Code Online (Sandbox Code Playgroud)