c#强制释放非托管资源

本文关键字:资源 释放 | 更新日期: 2023-09-27 18:16:36

我面临的挑战是,我正在编写一个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之后调用它,它都知道我之前已经调用过它,直到我重新启动应用程序。我希望每次我叫它的时候它都表现得像第一次叫它一样。每次创建helper的实例时,我需要在处理代码中包含什么才能完全从头开始,您知道吗?

c#强制释放非托管资源

我相信你的问题的根源是,一旦"mydll.dll"被加载到内存中,相同的实例,如果你愿意,被MyClass的每个实例使用。

如果不能修改底层库,则需要能够调用本机dll中的函数将其恢复到默认状态,或者需要能够在每次使用之间从内存中卸载它。根据你问题的背景,我敢打赌前一种选择是不可能的。你有两个选择,要么使用windows API来动态加载和卸载DLL:如何动态加载和卸载本地DLL文件?

…或者将此DLL包装在您制作的另一个exe中,因此,在构建时,您的服务将启动该exe,通过任意数量的手段与它交谈(您可以为此创建另一层WCF服务,stdin/out,命名管道,任何方便的东西),并在完成后关闭该exe。

我倾向于exe方法,以确保DLL是完全隔离的,没有办法破坏你的服务,再加你也有能力产生多个实例(每个WCF服务实例),如果你需要支持多个会话。此外,当您创建每个exe实例时,您可以获得进程ID并监视它是否崩溃,从而使您的服务更加健壮。