Как правило, вам не нужно освобождать общую библиотеку. Учтите, что CPython не предоставляет средства для выгрузки регулярного модуля расширения из памяти. Например, при импорте sqlite3 будет загружаться расширение _sqlite3 и общая библиотека sqlite3 в течение всего процесса. Разгрузочные расширения несовместимы с тем, как CPython использует указатели как идентификаторы объектов. Доступ к удаленному (и, возможно, повторно использованному) адресу будет неопределенным поведением.
Если вам необходимо разгрузить или перезагрузить общую библиотеку и уверены, что это безопасно, модуль расширения _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
Окна Пример
#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
на win7epX64 с py2.7x32 я могу загрузить мой конкретный длл 2 раза, но три или более попыток привести к 'WindowsError: [Ошибка -2147483645] Один или больше аргументов недействительны 'на' self._handle = _dlopen (self._name, mode) 'at' ctypes \ __ init__.py ", строка 365, в __init__' и python.exe сбой при выходе. ** Не ** случай со стандартной dll, такой как 'msvcrt40.dll', но все еще неясно, что на Земле возможно может пойти не так с моей другой dll. – n611x007
Я сомневаюсь, что отформатированное сообщение об ошибке имеет значение. Код ошибки '0x80000003', скорее всего, NT' STATUS_BREAKPOINT'. Возможно, он называется [DebugBreak'] (http://msdn.microsoft.com/en-us/library/windows/desktop/ms679297%28v=vs.85%29.aspx). Для получения трассировки стека вам понадобится отладчик, например windbg или cdb. Попробуйте воспроизвести ошибку за пределами Python в программной консоли C, которая вызывает «LoadLibrary». – eryksun
Определенно вам нужно выгрузить DLL.Это один из менее продуманных битов Python - он был разработан людьми Unix, которые, по-видимому, не знали, что вы не можете заменить DLL в Windows, если он загружен, как вы можете в Unix, и вам нужно иметь возможность разгружать в среде плагина, чтобы обновить собственный код без перезапуска всего приложения. –