Я портирую Облегченные коммуникации и маршаллинг с julia на lisp, так как у него лучший API. Я использовал глоток для генерации вызовов функций C.
Я хочу знать, безопасно ли это использование указателя C. вот функция создания:
(defun create-lcm (&optional (provider (null-pointer)))
(let* ((ptr (lcm_create provider))
(addr (cffi:pointer-address ptr)))
(tg:finalize ptr (lambda () (lcm_destroy (cffi:make-pointer addr))))
(if (NULL-POINTER-P ptr)
(error "lcm creation error"))
(%create-lcm :pointer ptr :provider provider
:file-descriptor (lcm_get_fileno ptr))))
Вопрос:
Любые другие замечания / советы приветствуются.
Заранее спасибо.
Функция финализатора относится к объекту, к которому она прикреплена, что предотвращает сборку мусора. Вы должны обернуть указатель в подходящее поле и прикрепить к нему финализатор (объекта, созданного в последней строке, вероятно, будет достаточно, если к указателю всегда обращаются только через него (т. Е. Никогда не назначается переменной или слоту в другом объект, который мог бы иметь более длительный срок службы)).
@jkiiski Так это прямо сейчас?
Вот несколько ошибок:
Не знаю, правильно ли это, но лучше:
(defun create-lcm (&optional (provider (null-pointer))
(let ((ptr (lcm_create provider)))
(when (null-pointer-p ptr)
(error “lcm creation error”))
(flet ((finaliser () (lcm_destroy ptr)))
(let ((result (%create-lcm :pointer ptr :provider provider
:file-descriptor (lcm_get_fileno ptr))))
(tg:finalize result #'finaliser)
result))))
Вот некоторые ошибки:
%create-lcm
или lcm_get_fileno
, то финализатор не запуститсякак указал @jkiiski. Функция финализатора не должна пытаться смотреть на объект, закрывая его, потому что это предотвратит сборку мусора. поэтому я должен использовать (cffi: make-pointer addr).
Финализатор закрывает ptr
, но он не закрывает финализатор для result
.
Возможно, вы захотите прочитать о cl-autowrap
, который используется, в частности, для обертывания SDL 2 в cl-sdl2
. Библиотека предоставляет тонкие оболочки вокруг указателей, которые уже освобождают память при финализации.
Я также думаю, что рекомендуемый способ использования финализаторов - использовать их только для очистки возможных утечек, учитывая, что у вас мало контроля над тем, когда и как выполняется функция очистки (например, какой поток, какая динамическая среда).
Один из способов управления памятью - заранее выделить ваши структуры и очистить их, когда они вам больше не нужны (пул). Или вы можете определить функцию или макрос, который определяет область видимости, так что память выделяется при входе в нее и освобождается при выходе, используя размотку-защиту:
(defmacro with-lcm ((context &rest options) &body body)
(let ((internal (gensym)))
`(let* ((,internal (create-lcm ,@options))
(,context ,internal))
(unwind-protect (progn ,@body)
(destroy-lcm ,internal)))))
c2ffi зависит от версии clang / llvm, поэтому мне не удалось его установить.
может предоставить несколько примеров «варианта использования». С уважением
Вероятно, вам не следует прикреплять финализатор к нулевому указателю. Это плохой стиль для
let
fd
наnil
, а потом наsetq
. Вы должны простоlet
, когда вам это нужно. Я не знаю достаточно о том, что вы делаете, чтобы сказать, правильно ли это