1

Consider I have an event listener in C# that waits for the data from the serial port, which are returned once captured by setting some status. In the main loop I look into that status and based on that I decide what to do next.

To do that I first write the command into the serial port and wait for the output by using Thread.Sleep method. By the time when the main thread is still in sleep mode, the event listener would already send the data and there is nothing done to handle that scenario.

Can anyone please tell me what would be the outcome in this condition and how to prevent it?

The code would be like

 bool status = false;
//main thread
private void Main()
{

    //some Code
    serialPort.Write("something");

    //Wait for 10 sec
    Thread.Sleep(10000);
    while(status == false)
    {
        // do something else
     }
}


   //Ignore the syntax, this is just to make people understand
   public void OndataReceived(object sender, EventArg arg)
   {
       //Function that recieve the data
       Receive();

       //change status to true
       status = true;

       return;
   }
Dhiraj Dhakal
  • 238
  • 1
  • 8

2 Answers2

0

The question is awkwardly worded, but if I understand it correctly, you are asking how you can avoid waiting ten seconds if the data is received earlier than that.

It is possible to use older synchronization objects, such as one of the WaitHandle subclasses, Monitor, or even a semaphore. But for this type of scenario, the current C# idiom is to use TaskCompletionSource, which provides both a waitable object and the option to return a result value at the same time.

For example:

TaskCompletionSource<bool> _result;

//main thread
private void Main()
{

    //some Code
    serialPort.Write("something");

    _result = new TaskCompletionSource<bool>();

    // Normally, one should "await" a Task. But in the Main() method, which
    // cannot be "async", we have to just wait synchronously.
    Task completed = Task.WhenAny(_result.Task,
        Task.Delay(TimeSpan.FromSeconds(10)).Result;

    // Don't check "_result.Result" unless the task has completed,
    // because otherwise the thread will block. If it is completed,
    // check "_result.Result" as the equivalent to examining the "status"
    // variable in the previous code example.
    while(!_result.IsCompleted || !_result.Result)
    {
        // do something else
    }
}

public void OndataReceived(object sender, EventArg arg)
{
    //Function that recieve the data
    Receive();

    //change status to true
    _result.SetResult(true);

    return;
}
Peter Duniho
  • 68,759
  • 7
  • 102
  • 136
  • Thanks Peter. Yes i want to say the same. But in my case if the data is sent when the main thread, which is started by doing Thread.Start(Main), is in the sleep mode, the whole windows service gets hang, so perhaps your answer would help me in that. And one more thing, I have lots of places where Thread.Sleep is used, will it be safe to use the new Task object instead ? – Dhiraj Dhakal Jul 18 '17 at 01:55
  • _"I have lots of places where Thread.Sleep is used, will it be safe to use the new Task object instead ?"_ -- Anywhere you have `Thread.Sleep()`, you really should seek alternative implementations (such as the above). The `Thread.Sleep()` method has never been a very good way to delay processing because it blocks the thread in which it's called, and modern C# has much better/useful ways to accomplish the same result. – Peter Duniho Jul 18 '17 at 02:19
0

What you really need is separate threads, a state machine, and delegates (callbacks). I wrote a decent example here: https://stackoverflow.com/a/38536373/2009197

Baddack
  • 1,947
  • 1
  • 24
  • 33