0

A lot of good programmers (including a lot of good members of Stackoverflow) are against using Application.DoEvents() whatever the circumstances are. Actually it is even supported with plenty of articles in the net, like this one, this famous debate on SO, ...

Though, I'm stuck in a case, where (I) think DoEvents() is the unique exit (lack of experience). That's enough as introduction, let's see some coding.

I have a 'serialPort' component to connect with a controller through serial communication, send command and wait for its response, that's all.

string response = "";
bool respFlag;

private string sendCommand(string command)
{
  respFlag = false;  //initialize respFlag

  serialPort1.Write(command);  // send the command

  Stopwatch timer = Stopwatch.StartNew(); // start a timer
  while(true)
  {
    // break from the loop if receive a response
    if(respFlag) break;  

    // timeOut error if no response for more than 500msec
    if(timer.ElapsedMilliseconds >= 500) break;

    // here comes the UGLY part
    Application.DoEvents(); 
  }

   return response;
}

in DataReceived method of my serialPort, I read the existing response and break the loop

private void serialPort1_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
  response = serialPort1.ReadExisting();

  // set the flag to true to exit the infinite loop in sendCommand
  respFlag = true; 
}

It's not exactly like this, but this is a sample code that shows how I sned-receive via serial communication, would you kindly show me where am I forcing myself into this pitfall?

Community
  • 1
  • 1
chouaib
  • 2,763
  • 5
  • 20
  • 35
  • What version of .NET are you running? – Scott Chamberlain Feb 06 '15 at 02:05
  • 1
    You'll find that `goto` is supported. So too is `catch (Exception ex)`. It doesn't mean that you should use them. So don't use `Application.DoEvents()` - it is evil. – Enigmativity Feb 06 '15 at 02:08
  • @Enigmativity, exactly man, I'm not debating use/don't use, I am seeking an alternative but can't find, that's why I asked here :) – chouaib Feb 06 '15 at 02:11
  • @ScottChamberlain I am on 4.5 , VS2012 – chouaib Feb 06 '15 at 02:12
  • 1
    @chouaib - Take a look at `async`/`await`, TPL, or Rx (Reactive Framework). – Enigmativity Feb 06 '15 at 02:50
  • @Enigmativity: thank you so much I will consider them too as my next (to learn) topics, I appreciate your time and effort – chouaib Feb 06 '15 at 02:52
  • @Enigmativity: I just notice this, can you please elaborate more on `dont use catch(exception ex)` ? – chouaib Feb 11 '15 at 05:38
  • @chouaib - Catch-all exception handling hides bugs in code - they can make the code run, even when it should have failed, and then can cause errors elsewhere in your program - or even corrupt the run-time. They basically make your code buggy. You should always only catch exceptions that are exceptional and that you can actually handle properly. – Enigmativity Feb 11 '15 at 05:47
  • @Enigmativity, I understand that it is not **NEVER** use `catch exception`, but use it **wisely** rather, example: In the accepted answer here I HAVE to catch the `TimeOutException`. is my understanding ok? – chouaib Feb 11 '15 at 05:50
  • @chouaib - Absolutely catch things like `TimeOutException` - that is a truly exceptional event that you can handle. I can't think of any place where a plain `catch (Exception ex)` should be used, except maybe at the very top-level class. – Enigmativity Feb 11 '15 at 07:00

3 Answers3

4

If you are using .NET 4.5 it is really easy to do with async/await and a TaskCompletionSource and async/await.

TaskCompletionSource<string> resultTcs = new TaskCompletionSource<string>();
private async Task<string> SendCommandAsync(string command)
{
    serialPort1.Write(command);  // send the command

    var timeout = Task.Delay(500);

    //Wait for either the task to finish or the timeout to happen.
    var result = await Task.WhenAny(resultTcs.Task, timeout).ConfigureAwait(false);

    //Was the first task that finished the timeout task.
    if (result == timeout)
    {
        throw new TimeoutException(); //Or whatever you want done on timeout.
    }
    else
    {
        //This await is "free" because the task is already complete. 
        //We could have done ((Task<string>)result).Result but I 
        //don't like to use .Result in async code even if I know I won't block.
        return await (Task<string>)result;
    }
}
private void serialPort1_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
    var response = serialPort1.ReadExisting();
    tcs.SetResult(response);

    //reset the task completion source for another call.
    resultTcs = new TaskCompletionSource<string>();
}
Scott Chamberlain
  • 124,994
  • 33
  • 282
  • 431
0

You should use the async I/O methods. Asynchronously wait for Task<T> to complete with timeout is a good example.

Community
  • 1
  • 1
Richard Schneider
  • 34,944
  • 9
  • 57
  • 73
0

I assume the answer is to run that loop in a different thread and send a message to the UI when the response is available. This assumes you cant do async IO for some reason

pm100
  • 48,078
  • 23
  • 82
  • 145