2014-02-14 2 views
4

мне было интересно, что, если бы я открыл мою собственную библиотеку DLL составлена ​​из пользовательских кода С, например:Free открытая ctypes библиотека Python

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»?

Спасибо!

ответ

8

Как правило, вам не нужно освобождать общую библиотеку. Учтите, что 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 
+0

на 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

+1

Я сомневаюсь, что отформатированное сообщение об ошибке имеет значение. Код ошибки '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

+0

Определенно вам нужно выгрузить DLL.Это один из менее продуманных битов Python - он был разработан людьми Unix, которые, по-видимому, не знали, что вы не можете заменить DLL в Windows, если он загружен, как вы можете в Unix, и вам нужно иметь возможность разгружать в среде плагина, чтобы обновить собственный код без перезапуска всего приложения. –