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的实例时,我需要在处理代码中包含什么才能完全从头开始,您知道吗?
我相信你的问题的根源是,一旦"mydll.dll"被加载到内存中,相同的实例,如果你愿意,被MyClass的每个实例使用。
如果不能修改底层库,则需要能够调用本机dll中的函数将其恢复到默认状态,或者需要能够在每次使用之间从内存中卸载它。根据你问题的背景,我敢打赌前一种选择是不可能的。你有两个选择,要么使用windows API来动态加载和卸载DLL:如何动态加载和卸载本地DLL文件?
…或者将此DLL包装在您制作的另一个exe中,因此,在构建时,您的服务将启动该exe,通过任意数量的手段与它交谈(您可以为此创建另一层WCF服务,stdin/out,命名管道,任何方便的东西),并在完成后关闭该exe。
我倾向于exe方法,以确保DLL是完全隔离的,没有办法破坏你的服务,再加你也有能力产生多个实例(每个WCF服务实例),如果你需要支持多个会话。此外,当您创建每个exe实例时,您可以获得进程ID并监视它是否崩溃,从而使您的服务更加健壮。