Haskell中的外部C指针之后的清理

Haskell中的外部C指针之后的清理,c,haskell,fluidsynth,C,Haskell,Fluidsynth,我围绕绑定FluidSync库编写了一组实用程序函数: 模块FSUtilities,其中 进口管制 导入系统目录 进口外国货 进口外国货 导入外国C.C.类型 输入外文字符串 导入绑定.fluidSync newtype Settings=设置(外国PTR C’流体设置) 新型合成=合成(国外流体合成) 类型通道=Int 类型Key=Int 类型速度=Int initSynth::IO Synth initSynth=createSettings>>= 更改设置STR“音频驱动程序”“alsa”

我围绕绑定FluidSync库编写了一组实用程序函数:

模块FSUtilities,其中
进口管制
导入系统目录
进口外国货
进口外国货
导入外国C.C.类型
输入外文字符串
导入绑定.fluidSync
newtype Settings=设置(外国PTR C’流体设置)
新型合成=合成(国外流体合成)
类型通道=Int
类型Key=Int
类型速度=Int
initSynth::IO Synth
initSynth=createSettings>>=
更改设置STR“音频驱动程序”“alsa”>>=
changeSettingInt“合成复调”64>>=
(\s->CreateSynch s>>=createDriver s)>>=
负载SF“GS.sf2”
createSettings::IO设置
创建设置=
新的流体设置>>=
newForeignPtr p'delete_fluid_设置>>=(纯$!)。设置
changeSettingStr::字符串->字符串->设置->IO设置
更改设置STR k v(设置s)=
使用ForeignPTR s$\ptr->
用去势k$\cstr->
使用Castring v$\cstr'->
c“流体设置”设置TR ptr cstr cstr'>>
(纯$!设置)
changeSettingInt::String->Int->Settings->IO设置
更改设置输入k v(设置s)=
使用ForeignPTR s$\ptr->
用去势k$\cstr->
c'流体设置设置ptr cstr(来自积分v)>>
(纯$!设置)
CreateSynch::设置->IO合成器
CreateSynch(设置)=
使用外国PTR s'c'new_fluid_synth>>=
newForeignPtr p'delete_fluid_synth>>=(纯$!)。合成器
createDriver::设置->合成->IO合成
createDriver(设置集)(合成同步)=
withForeignPtr集合$\ptr->
withForeignPtr syn$\ptr'->
c'new_fluid_audio_driver ptr ptr'>>=
newForeignPtr p'delete_fluid_audio_driver>>
(纯$!Synth syn)
loadSF::String->Synth->IO Synth
loadSF路径(Synth-syn)=
withForeignPtr syn$\s->
生成绝对路径>>=\p->
withCAString p$\p'->
c'fluid\u synth\u sfload s p'1>>=
\c->如果c==(-1),则出现错误“loadSF:无法加载SoundFont”
else putStrLn“加载SF:SoundFont加载”>>
(纯$!Synth syn)
注意:通道->按键->速度->合成->IO()
关于c k v(合成ptr)的注记=
withForeignPtr ptr$\syn->
c'fluid_synth_noteon syn c'k'v'>>纯()
其中c'=从积分c
k'=积分k
v'=从积分v
justPlay::频道->按键->IO()
只需播放c k=initSynth>>=c k 127上的注释
justPlay':频道->按键->IO合成器
只需播放'c k=initSynth>=\s->c k 127 s>>纯s上的注释
justPlay
justPlay'
函数用于说明问题。当我从ghci调用
justPlay
时,我会得到随机的segfaults(不一致,大约30%的时间),而
justPlay'
从不这样做(但是在一系列调用之后,由于悬挂着
Synth
s,我的系统内存很快就被填满了。我想这是因为当
Synth
不再被引用时,我没有清理自己的内存,但我认为在创建
Synth
时,应该使用终结器函数调用
newForeignPtr
自动处理


我是哈斯克尔的新手,我不懂C,所以我正在努力摸索解决办法。处理这种情况的正确方法是什么?

很难说到底是什么导致了这次坠机,但至少有一件明显错误的事情。发生在:

在释放FluidSync实例之前,应删除合成器实例的其他用户,如音频和MIDI驱动程序

在您的情况下,终结器的顺序没有定义,因此合成器可以在驱动程序之前删除。可能其他对象的生命周期也有限制


要显式地完成外部指针,请使用
finalizeForeignPtr

坦率地说,如果您是Haskell的新手,并且不懂C,那么从一个非平凡的FFI绑定开始似乎不是非常谨慎的做法,它结合了两种语言的缺陷。这个示例远远不是最小的,因此很难看出问题所在(特别是因为这些C函数中的每一个都有自己的指针参数生命周期要求)但是有一件非常明显的事情是,
c'new\u fluid\u audio\u driver ptr ptr'>=newForeignPtr p'delete\u fluid\u audio\u driver>.
-这里你创建了一个带有外部调用的指针,并立即丢弃它!@user2407038抱歉,我无法进一步隔离这个问题,因为所有这些调用都是初始化fluidSync和甚至尝试获取声音。我放弃了你提到的
newForeignPtr
行,因为我真的不使用它的输出,但这并没有改变任何东西。我很确定这是因为
Synth
指针没有被正确释放。当播放声音的函数通过它使用的
Synth
时,我没有得到segfaults,但我f I
return()
在播放函数结束时,事情会中断。请注意
justPlay
justPlay'
的类型签名。