【问题标题】:C# Force Unmanaged Resources To Be ReleasedC# 强制释放非托管资源
【发布时间】:2016-11-07 14:10:51
【问题描述】:

我面临的挑战是我正在编写一个 WCF 服务,它本质上是多线程的,可以与我知道不是线程安全的 C 库一起工作,而且我无法影响我正在调用的库.我正在调用的库有一个初始化方法来配置硬件和设置回调处理程序。

如果我在控制台应用程序中执行此过程,它运行得非常好,因为它是在单个线程上。

为了克服这些挑战,我创建了一个辅助类,它实现了 IDisposable 来设置硬件、进行调用并希望在完成后自行拆除。

示例帮助类:

public class MyClass 
{
[DllImport("mydll.dll", CallingConvention = CallingConvention.Cdecl)]
    private static extern void Setup(ushort var_one, ushort var_two);

    [DllImport("mydll.dll", CallingConvention = CallingConvention.Cdecl)]
    private static extern int Initialise(int port_num, int short_timeout, int long_timeout,
                                                  TXN_CALLBACK callback);

    [DllImport("mydll.dll", CallingConvention = CallingConvention.Cdecl)]
    private static extern IntPtr GetDeviceStatus();

    [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
    public delegate void TXN_CALLBACK(int size, [MarshalAs(UnmanagedType.LPStr)] string the_data);

    private int Setup(ushort var_one, ushort var_two);
    {
        Setup(var_one, var_two);
        int foo= Initialise(0, shorttimeout, longtimeout, txn_callback);
        return foo;
    }      

    public MyStruct GetStatus()
    {

        Setup(0, 0);
        return PtrToStruct<MyStruct>(GetDeviceStatus());            
    }

    private static void txn_callback(int size, string the_data)
    {
         // Do something with the data
    }

    private static T PtrToStruct<T>(IntPtr ptr)
    {
        if (ptr == IntPtr.Zero)
        {
            // Invalid pointer returned
            return default(T);
        }

        return Marshal.PtrToStructure<T>(ptr);
    }
}

调用代码(WCF服务):

using (MyClass class = new MyClass())
{
    return class.GetStatus();
}

我省略了 IDisposable 代码,因为它已被设置为由 Visual Studio 创建的默认一次性模式。就目前而言,每次我在第一次之后调用 GetStatus 时,它都知道我之前已经调用过它,直到我重新启动应用程序。我希望它每次调用它时都表现得像第一次一样。每次创建帮助程序的实例时,我需要在处置代码中包含什么以完全从头开始?

【问题讨论】:

  • 如果 dll 不是线程安全的,那么实现处理模式对内部损坏状态的可能性没有多大帮助。您需要确保只有一个线程通过生成另一个进程或使用多个重命名的 dll 做一些骇人听闻的事情来访问库
  • 我尝试使用 lock() 包装所有服务,以便不能从多个线程调用该库,但它似乎是明智的,因为它之前已经被进程使用过。跨度>

标签: c# wcf interop idisposable


【解决方案1】:

我相信您问题的根源在于,一旦将“mydll.dll”加载到内存中,MyClass 的每个实例都会使用同一个实例(如果您愿意的话)。

鉴于您无法修改底层库,您需要能够调用本机 dll 中的函数以将其恢复到默认状态,或者您需要能够在每次使用之间从内存中卸载它。根据您的问题的上下文,我打赌前一个选项是不可能的。您有几个选择,或者使用 Windows API 动态加载和卸载 DLL: How to dynamically load and unload a native DLL file?

...或将此 DLL 包装在您制作的另一个 exe 中,因此,在构建时,您的服务将启动该 exe,通过多种方式与其通信(您可以为此创建另一层 WCF 服务,stdin /out,命名管道,任何方便的东西),并在完成后关闭 exe。

我倾向于使用 exe 方法来确保 DLL 完全隔离并且不会破坏您的服务,此外,如果您需要支持多个会话,您还可以生成多个实例(针对每个 WCF 服务实例) .此外,当您创建每个 exe 实例时,您还可以获取进程 ID 并监控它的崩溃情况,从而使您的服务更加健壮。

【讨论】:

    猜你喜欢
    • 2015-05-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-10-01
    • 2013-02-02
    • 2015-10-13
    • 1970-01-01
    相关资源
    最近更新 更多