5

一般信息

我目前正在试验 Haskell 的 C->Haskell (C2HS) 接口生成器。乍一看,这真是太棒了,我extern C在短短几个小时内就连接了一个相当复杂的 C++ 库(使用一个小的 -wrapper)。(而且我以前从未做过任何 FFI。)

只有一个问题:如何释放 C/C++ 库中分配的内存?我{#pointer ... foreign #}C2HS 文档中找到了,这看起来与我所追求的完全一样。由于我的 C-wrapper 将 C++ 库转换为具有引用透明性和功能接口的库,因此 Haskell 存储管理器应该能够为我完成艰苦的工作:-)。不幸的是,我无法让这个工作。为了更好地解释我的问题,我在 GitHub 上建立了一个小型演示项目,它与 C/C++ 库+包装器具有相同的属性,但没有开销。如您所见,该库与pure unsafeFFI 一起使用是完全安全的。

演示项目

在 GitHub 上,我创建了一个小型演示项目,组织如下:

C 库

C 库非常简单且无用:您可以将整数传递给它,然后可以[0..n]从库中获取尽可能多的整数(当前)。记住:这个库没用,只是一个演示。该接口也非常简单:该函数LTIData lti_new_data(int n)将(在传递一个整数之后)返回某种不透明的对象,其中包含 C 库的已分配数据。该库还有两个访问器函数int lti_element_count(LTIData data)int lti_get_element(LTIData data, int n)前者将返回元素的数量,后者将返回元素n。啊,最后但并非最不重要的一点是,图书馆的用户应该在使用它之后释放不透明LTIDatavoid lti_free_data(LTIData data).

低级 Haskell 绑定

低级 Haskell 绑定是使用 C2HS 设置的,您可以在

高级 Haskell API

为了好玩,我还设置了一种使用低级 API 绑定的高级 Haskell API和一个使用高级 API 的简单驱动程序。使用驱动程序和例如 valgrind 可以很容易地看到泄漏的内存(对于每个参数p_1, p_2, ..., p_n,库都会进行\sum_{i = 1..n} 1 + p_i分配;如下所示很容易观察到):

$ valgrind dist/build/TestHsLTI/TestHsLTI 100             2>&1 | grep -e allocs -e frees
==22647==   total heap usage: 184 allocs, 74 frees, 148,119 bytes allocated

$ valgrind dist/build/TestHsLTI/TestHsLTI 100 100         2>&1 | grep -e allocs -e frees
==22651==   total heap usage: 292 allocs, 80 frees, 181,799 bytes allocated

$ valgrind dist/build/TestHsLTI/TestHsLTI 100 100 100     2>&1 | grep -e allocs -e frees
==22655==   total heap usage: 400 allocs, 86 frees, 215,479 bytes allocated

$ valgrind dist/build/TestHsLTI/TestHsLTI 100 100 100 100 2>&1 | grep -e allocs -e frees
==22659==   total heap usage: 508 allocs, 92 frees, 249,159 bytes allocated

演示的当前状态

您应该能够通过简单地键入来克隆、编译和运行项目git clone https://github.com/weissi/c2hs-experiments.git && cd c2hs-experiments && cabal configure && cabal build && dist/build/TestHsLTI/TestHsLTI

那么又是什么问题呢?

问题是该项目只使用而不是使用 C2HS 的Foreign.Ptr“托管”版本,我无法让它工作。在演示项目中,我还添加了一个文件,尝试使用这些外部指针,但它不起作用:-(。我非常努力地尝试,但没有成功。Foreign.ForeignPtr{#pointer ... foreign #}.chs

还有一件事我也不明白:如何使用 C2HS 告诉 GHC 如何释放图书馆的数据。演示项目的库提供了一个函数void lti_free_data(LTIData data),应该调用它来释放内存。但是GHC猜不到!?!如果 GHC 使用常规 a free(),则并非所有内存都会被释放:-(。

4

1 回答 1

3

问题已解决:我发现这个文件在互联网上做了类似的事情并且能够解决它:-)。

它所需要的只是一些样板编组代码:

foreign import ccall "lib_to_interface.h &lti_free_data"
  ltiFreeDataPtr :: FunPtr (Ptr (LTIDataHs) -> IO ())


newObjectHandle :: Ptr LTIDataHs -> IO LTIDataHs
newObjectHandle p = do
  fp <- newForeignPtr ltiFreeDataPtr p
  return $ LTIDataHs fp

这是文件的最终托管 ( ForeignPtr) 版本.chs

于 2012-08-22T11:10:31.777 回答