【问题标题】:Handling the data sent from the event handlers during sleep mode of the main thread C#在主线程 C# 的睡眠模式期间处理从事件处理程序发送的数据
【发布时间】:2017-07-19 02:56:37
【问题描述】:

假设我在 C# 中有一个事件侦听器,它等待来自串行端口的数据,一旦通过设置某些状态捕获这些数据就会返回。在主循环中,我会查看该状态并根据该状态决定下一步该做什么。

为此,我首先将命令写入串行端口并使用 Thread.Sleep 方法等待输出。当主线程仍处于睡眠模式时,事件侦听器已经发送数据并且没有任何操作来处理这种情况。

谁能告诉我在这种情况下会有什么结果以及如何预防?

代码是这样的

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

【问题讨论】:

  • 看看 Manual- 和 AutoResetEvent
  • 创建您的自定义事件,从OndataReceived 方法内部触发它,并在我看来执行该方法的后续步骤

标签: c# multithreading serial-port


【解决方案1】:

这个问题措辞很尴尬,但如果我理解正确的话,你是在问,如果早于十秒收到数据,如何避免等待十秒。

可以使用较旧的同步对象,例如WaitHandle 子类之一、Monitor,甚至是信号量。但是对于这种场景,目前的 C# 习惯用法是使用TaskCompletionSource,它既提供了一个可等待的对象,又提供了同时返回一个结果值的选项。

例如:

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

【讨论】:

  • 谢谢彼得。是的,我想说同样的话。但在我的情况下,如果在通过执行 Thread.Start(Main) 启动的主线程处于睡眠模式时发送数据,则整个 Windows 服务都会挂起,所以也许你的回答会帮助我。还有一件事,我有很多使用 Thread.Sleep 的地方,改用新的 Task 对象是否安全?
  • “我有很多使用 Thread.Sleep 的地方,用新的 Task 对象代替是否安全?” -- 任何你有Thread.Sleep()的地方,你真的应该寻找替代实现(例如上面的)。 Thread.Sleep() 方法从来都不是延迟处理的好方法,因为它阻塞了调用它的线程,而现代 C# 有更好/有用的方法来完成相同的结果。
【解决方案2】:

您真正需要的是单独的线程、状态机和委托(回调)。我在这里写了一个不错的例子:https://stackoverflow.com/a/38536373/2009197

【讨论】:

    猜你喜欢
    • 2015-03-18
    • 1970-01-01
    • 2021-06-15
    • 1970-01-01
    • 2014-08-14
    • 1970-01-01
    • 1970-01-01
    • 2011-01-25
    • 2012-11-21
    相关资源
    最近更新 更多