0

I am trying to setup some comms with a device where you can send a command and receive a response. I do however want to ensure that I control a timeout flag to prevent indefinite wait times.

I did something like this:

private volatile EventWaitHandle _signal;

public void Send()
{
    // Do something

    _signal.WaitOne(30000);

    // Continue with something else

    _signal.Reset();
}

public void Receive() 
{
    _signal.Set();
}

My question is, if I have multiple threads (let's say 2 for this example) that can access the Send method and the following scenario:

Thread A:

// Sends a "listen" command, but no response is received 
Send();

Thread B:

// Sends a "cancel" command and response (success) is received
Send();

I get inconsistent results, i.e. sometimes both threads continue when I get a response for the second command (cancel) which I can understand, but sometimes the first thread will hit the 30000ms timeout - which I cannot explain.

Any advice as to what I am missing and/or doing wrong?

NubieJ
  • 575
  • 2
  • 9
  • 21
  • Aren't you using `AutoResetEvent`? You need to use `ManualResetEvent`, otherwise it will reset automatically when the waiting thread is signaled. In fact, you probably don't really want to use wait handles at all. There's most likely a better solution to what you're trying to do, especially if you can afford to use .NET 4.5.1. Why is this multi-threaded in the first place? – Luaan Apr 22 '14 at 08:01
  • Using ManualResetEvent and multi-threaded in order to cancel a pending response, i.e. command sent, but I need to be able to cancel it before I receive a response. (Limited to .Net 4.0 unfortunately) – NubieJ Apr 22 '14 at 08:21
  • 1
    .NET 4.0 should still be enough to enable you to use asynchronous I/O for the purpose, although 4.5 makes this much much easier. – Luaan Apr 22 '14 at 09:14

1 Answers1

3

An EventWaitHandle is not the appropriate synchronization object here. You require mutual exclusion so that only one thread can be in a state where it sent a command and is waiting for the response. In other words, threads must strictly take their turn to talk to the device.

A ManualResetEvent doesn't give you that guarantee, as soon as you call Set() then all the threads that are blocking on the WaitOne() call will be unblocked. If that's more than one then your program will malfunction when two or more threads try to send a command at the same time.

A Mutex provides MUTual EXclusion. That's how it got its name.

Hans Passant
  • 922,412
  • 146
  • 1,693
  • 2,536
  • This makes sense, but if I exclude any other threads how would I cancel the current request (on the thread that is blocking)? – NubieJ Apr 22 '14 at 08:41
  • You gave no hint whatsoever in your question what it might be blocking on. It is waiting for some kind of I/O request to complete, perhaps. Make it wait on a cancel request as well with, say, WaitAny(). That's a guess. You then release the Mutex as well of course. – Hans Passant Apr 22 '14 at 08:44