Как завершить работу с lisp: struct, содержащим указатель?

Я портирую Облегченные коммуникации и маршаллинг с 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))))

Вопрос:

  • Как правильно завершить указатель C?
  • Как сделать тест на это?

Любые другие замечания / советы приветствуются.

Заранее спасибо.

Вероятно, вам не следует прикреплять финализатор к нулевому указателю. Это плохой стиль для letfd на nil, а потом на setq. Вы должны просто let, когда вам это нужно. Я не знаю достаточно о том, что вы делаете, чтобы сказать, правильно ли это

Dan Robertson 05.08.2018 18:17

Функция финализатора относится к объекту, к которому она прикреплена, что предотвращает сборку мусора. Вы должны обернуть указатель в подходящее поле и прикрепить к нему финализатор (объекта, созданного в последней строке, вероятно, будет достаточно, если к указателю всегда обращаются только через него (т. Е. Никогда не назначается переменной или слоту в другом объект, который мог бы иметь более длительный срок службы)).

jkiiski 05.08.2018 20:52

@jkiiski Так это прямо сейчас?

I.Omar 06.08.2018 03:47
Мутабельность и переработка объектов в Python
Мутабельность и переработка объектов в Python
Объекты являются основной конструкцией любого языка ООП, и каждый язык определяет свой собственный синтаксис для их создания, обновления и...
3
3
189
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Вот несколько ошибок:

  1. Присоединение финализатора к указателю, который может быть нулевым
  2. Я не уверен, что вам разрешено прикреплять финализатор к чужому указателю. Может быть вы.
  3. Будьте осторожны с финализаторами и gc. Если финализатор ссылается на объект, который он завершает, тогда объект и его финализатор поддерживают друг друга в живых (они не могут быть собраны сразу, потому что финализатор может где-то хранить ссылку на объект, и тогда этот объект будет живым и поэтому не должен '' t были доработаны.

Не знаю, правильно ли это, но лучше:

(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))))

Вот некоторые ошибки:

  1. Если есть ошибка от %create-lcm или lcm_get_fileno, то финализатор не запустится

как указал @jkiiski. Функция финализатора не должна пытаться смотреть на объект, закрывая его, потому что это предотвратит сборку мусора. поэтому я должен использовать (cffi: make-pointer addr).

I.Omar 06.08.2018 11:21

Финализатор закрывает ptr, но он не закрывает финализатор для result.

Dan Robertson 06.08.2018 13:48

Возможно, вы захотите прочитать о 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, поэтому мне не удалось его установить.

I.Omar 06.08.2018 11:45

может предоставить несколько примеров «варианта использования». С уважением

I.Omar 06.08.2018 11:48

Другие вопросы по теме