views:

59

answers:

1

Currently, we use an unmanaged DLL from a vendor that allows us to access a particular instrument. The particular function of interest is specified in a header file as this:

extern "C" short CCONV acq_get_board_count ();

In my application, I have the pinvoke statement:

public class bograms
{
    [DllImport("bograms.dll", EntryPoint = "acq_get_board_count", CallingConvention = CallingConvention.StdCall)]
    public static extern short acq_get_board_count();
}

Now, in my code I am attempting to handle redundancy, so I create a timer that attempts to keep things running:

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
        }
    }
}

The first tick of the timer, it gets zero boards (presumably because the hardware is not finished initializing), and prints both messages to the console. However, the second tick, I get an APPCRASH error 0xc0000005 in the bograms.dll, which I've found to be an Access Violation error. Putting try/catch around the call does not catch the error. The first line is in the console, the second line is not. When debugging the dump file (to the best of my limited knowhow), the error seems to occur on this call.

Is my pinvoke statement wrong? It's such a simple function that I can't believe it would be, but am I missing something? Is the threading due to the timer causing some type of problem?

I'm guessing the first call puts it into some type of state that results in the second call's failure, especially when considering the hardware initialization going on behind the scenes. If this is the case, is there any way to unload the driver DLL so it can reset back to the initial state it should be in?

Or are there any other things you can think of?

+2  A: 

One thing that immediately comes to mind is whether the API can be used safely across threads. The System.Threading.Timer callbacks come in on a ThreadPool thread so it could be different each time. Some APIs have thread affinity requirements which means that they can only be called from a single thread. In lieu of that there still may be some concurrency problem if two calls to the same API occur simultaneously. In the end you may find out that the problem has nothing to do with threading. I am just trying to present one possible explanation.

Brian Gideon
I know this has been awhile, but I've been testing this theory for the past month, and I think you're right about the thread affinity thing, especially since I'm using a Timer to accomplish the KeepAlive task. The instrument's driver must be storing a bit of information upon the first call, and on the second call (which occurs on a different thread) it tries to access that bit of memory, and fails with a violation. But, I have no clue how to solve this... Do I change the timer method to a single loop using `Thread.Sleep()` to delay each KeepAlive? I have heard bad things about Sleeping...
drharris