最近一直被C#調用Haskell時的“嘗試讀取或寫入受保護的內存”問題所困擾(詳見C#調用haskell遭遇Attempted to read or write protected memory,C#調用haskell時的“嘗試讀取或寫入受保護的內存”問題),而且困在其中,越陷超深,無法自拔,差點棄用C#解決我們面臨的問題。
問題是這樣的,只要在Haskell代碼中對字符串進行操作,在C#調用時就會引發異常:
An unhandled exception of type 'System.AccessViolationException' occurred in Unknown Module.
Additional information: Attempted to read or write protected memory. This is often an indication that other memory is corrupt.
示例Haskell代碼如下:
如果直接返回字符串,則一切正常,示例Haskell代碼如下:
C#調用示例代碼:
class Native { [DllImport("libpandoc", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Unicode)] public static extern IntPtr markdownToHtml(byte[] markdown); } public class Processor { public string Process(string text) { var intPtr = Native.markdownToHtml(System.Text.Encoding.UTF8.GetBytes(text)); var html = Marshal.PtrToStringAnsi(intPtr); return html; } }
你也許會問——吃飽撐著了,為什麼要用C#調用Haskell?
沒撐著!因為史上最強大的Markdown引擎pandoc就是用Haskell開發的,不是C#,不是Java,不是PHP,不是Python,也不是C/C++,更不是Objective-C。真正要比的不是語言,而且是用語言開發出來的東西。
你也許要問——很多人看不起的微軟家的C#能調用高上大的Haskell?
當然能!而且經過了實際驗證,詳見經過實際驗證的C#調用Haskell的方法。雖然是通過FFI(ForeignFunctionInterface),借助C編譯成非托管的dll,但不管怎麼樣,C#做到了。
但當我們用C#調用Haskell解決實際問題時,遭遇了“Attempted to read or write protected memory. ”問題,反復折騰找不到解決之道,處於絕望中,以為“C#可以調用Hakell"是一個“騙局”。
。。。
今天上午,當我們把編譯好的程序從Windows Server 2008 R2復制到Windows Server 2012上運行時,奇跡竟然出現了——運行正常,並且得到了正確的結果。
這時你也許又要問——不是自找麻煩嗎,為什麼不一開始就用Windows Server 2012?
不是自找麻煩,是麻煩自己找上門的。因為編譯Haskell代碼需要安裝Haskell Platform(集成了ghc),而Haskell Platform不能在Windows Server 2012正常安裝,只能被迫在Windows Server 2008上安裝(當時也被折騰了)。
萬萬沒有想到的是,Windows Server 2008上編譯出來的程序不能在Windows Server 2008上正常運行,卻奇跡般地能在Windows Server 2012上能正常運行。這是不是Windows的一個坑呢?
由此想到我們在阿裡雲上曾經遭遇的“黑色10秒”問題,是因為Windows Server 2008在WAS(Windows Process Activation Service)中使用了spinlock,而虛擬化技術對spinlock支持不好,最終也是通過換用Windows Server 2012解決了問題。這雖然不能說是Windows Server 2008的一個坑,但說明了一點——使用Windows Server,2008要小心!
查看本欄目