目前,我们使用来自供应商的非托管DLL,允许我们访问特定的工具。感兴趣的特定功能在头文件中指定为:
extern "C" short CCONV acq_get_board_count ();
在我的申请中,我有pinvoke声明:
public class bograms
{
[DllImport("bograms.dll", EntryPoint = "acq_get_board_count", CallingConvention = CallingConvention.StdCall)]
public static extern short acq_get_board_count();
}
现在,在我的代码中,我试图处理冗余,所以我创建了一个试图让事情继续运行的计时器:
public class Instrument
{
private System.Threading.Timer keepAliveTimer;
public Instrument()
{
keepAliveTimer = new Timer(new TimerCallback(this.KeepAlive), null, 0, 300000);
}
void KeepAlive(object state)
{
if(instrumentIsUninitialized) // some check that accomplishes this
{
Console.WriteLine("Some status statements"); // in console
short numBoards = bograms.acq_get_board_count();
Console.WriteLine("Initialization caught {0} boards.", numBoards); // not in console
}
}
}
计时器的第一个滴答,它得到零板(可能是因为硬件没有完成初始化),并将两个消息都打印到控制台。但是,第二个滴答,我在bograms.dll
中得到APPCRASH错误0xc0000005,我发现这是一个访问冲突错误。在调用周围放置try / catch不会发现错误。第一行是在控制台中,第二行不是。在调试转储文件时(尽我所知),这次调用似乎发生了错误。
我的pinvoke声明错了吗?它是如此简单的功能,我无法相信它,但我错过了什么?由于计时器导致某些类型的问题导致线程化吗?
我猜测第一次调用会将其置于某种类型的状态,导致第二次调用失败,尤其是在考虑幕后硬件初始化时。如果是这种情况,有没有办法卸载驱动程序DLL,以便它可以重置回它应该在的初始状态?
或者你还能想到其他什么吗?
答案 0 :(得分:2)
立即想到的一件事是API是否可以跨线程安全使用。 System.Threading.Timer
回调来自ThreadPool
线程,因此每次都可能不同。某些API具有线程关联性要求,这意味着它们只能从单个线程调用。代替这一点,如果同时发生对同一API的两次调用,仍可能存在一些并发问题。最后,您可能会发现问题与线程无关。我只是想提出一个可能的解释。