We are attempting to read information from a hardware device, and the only way to do this is to communicate with it through a closed-source, native DLL the hardware manufacturer provides. They also provide a .NET wrapper to access the DLL, which the wrapper method of concern is simplified below:
[DllImport("hardware_mfg.dll")]
private static extern int hardware_command_unicode(MarshalAs(UnmanagedType.LPWStr)] string outdata, uint outcount, [MarshalAs(UnmanagedType.LPWStr)] StringBuilder indata, uint maxdata, ref uint incount);
public static int HardwareCommand(string senddata, StringBuilder recdata)
{
uint incount = 0;
return HardwareWrapper.hardware_command_unicode(senddata, (uint)senddata.Length, recdata, (uint)recdata.Capacity, ref incount);
}
The code calling the HardwareWrapper.HardwareCommand function is:
// This method gets called from a DispatcherTimer.Tick event
public static int SendCommand(string command, StringBuilder buffer)
{
lock (_locker)
{
try
{
if (_commandInProgress)
{
// This exception gets thrown
throw new InvalidOperationException("This should not be possible");
}
_commandInProgress = true;
// InvalidOperationException gets thrown while previous call to HardwareCommand here has not yet returned
var result = HardwareWrapper.HardwareCommand(command, buffer);
return result;
}
finally
{
_commandInProgress = false;
}
}
}
The confusing part is that the InvalidOperationException gets thrown. When the main thread enters the var result = HardwareWrapper.HardwareCommand(...)
it is possible for the method to be called again, and enter the same function before the first call returns. It is intermittent that the exception gets thrown, but letting this code run for 15-30 seconds will be enough to have the exception happen.
- How is it possible for the main thread to exist twice in one method?
- What can be done to prevent this from happening?
EDIT 1: Move lock to outer scope