我面临的挑战是我正在编写一个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之后就知道我已经调用它,直到我重新启动应用程序。我希望每次打电话都表现得好像是第一次。我需要在处理代码中包含哪些想法,以便在每次创建助手实例时从头开始完全开始?
答案 0 :(得分: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并监视崩溃,从而使您的服务更加健壮。