【问题标题】:SerialPort wait for response串口等待响应
【发布时间】:2012-07-31 16:41:18
【问题描述】:

.NET 4.0 中是否有机会等待响应然后返回响应?

目前我正在这样做,但它不是很好,我不喜欢它:

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
        byte[] options = new byte[]{1,1,0};
        COMManager mgr = new COMManager("COM1");

        byte[] result = mgr.GetResponse(options);
    }
}

还有我的 COM 管理器类 (我必须在单独的类(dll)中进行操作):

public class COMManager
    {
        SerialPort sp = null;
        byte[] result = null;
        bool completed = false;

        public COMManager(string comport)
        {
            sp = new SerialPort(comport);
            sp.DataReceived +=new SerialDataReceivedEventHandler(sp_DataReceived);
        }

        public byte[] GetResponse(byte[] option)
        {
            sp.Write(option, 0, option.Length);
            //I don't like the way...
            while (!completed) { }
            completed = false;
            return result;
        }

        void  sp_DataReceived(object sender, SerialDataReceivedEventArgs e)
        {
            result = new byte[sp.BytesToRead];
            sp.Read(result, 0, sp.BytesToRead);
            completed = true;
        }
    }

在 .NET 4.5 中,我们可能有机会使用“await”语句。但是对于当前项目,我们只允许使用 .NET 4.0。 有什么想法吗?

【问题讨论】:

    标签: c# port


    【解决方案1】:

    对于您的原始问题,要阻止正在执行的线程,您可以使用ManualResetEventAutoResetEvent,在获得您的回复后将获得Set。页面上有很好的解释。

    对于线程,经验法则是,如果您不是非常清楚自己在做什么,请不要这样做。

    当您可以访问事件时同步阻塞似乎是一种浪费。考虑到数据是一个流,这最终可能难以维护抽象。

    上面有一个关于here的例子对上述想法的更详细的解释。

    您也可以与TaskCompletionSource 异步执行此操作。您可以调用SetResult,而不是set,然后等待.Task,但想法几乎相同。

    【讨论】:

    • 嗨,阿斯蒂。感谢您的回复。我以前从未使用过 ManualResetEvents。所以我添加“私有静态 ManualResetEvent mre = new ManualResetEvent(false);”到我的 COMManager 类,“mre.Reset()”将替换我的 while 循环。在 dp_DataReceived 而不是 completed = true 我设置 mre.Set() 对吗?
    • @user1011394 是的,基本上。不过不要将其声明为静态的。
    • 您还可以使用 AutoResetEvent,它会在您设置后自动重置,因此如果您愿意,您不必调用 Reset。
    • @PrashantPimpale 哎呀,现在才看到你的消息。给你写了一个答案。
    【解决方案2】:

    如果您不想异步读取,则使用 DataReceived 事件是没有意义的。只需在 GetResponse() 中直接调用 Read() 方法即可。

    注意你不能假设你会得到一个完整的响应,你不能忽略 Read() 的返回值。它通常只返回几个字节,串行端口非常慢。所以一定要继续调用 Read() 直到你得到整个响应。

    【讨论】:

    • 嗨 Hans Passant,这是一个异步调用。首先,我必须写入字节(将其发送到设备),其次,设备将解释它并向我发送单独的响应。
    【解决方案3】:

    干净的方法是等待AutoResetEvent 并等待接收回调发出信号。

    通过使用此方法创建包装器,您可以在 .Net 的每个版本中有效地await

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2013-05-15
      • 2015-11-18
      • 1970-01-01
      • 2017-01-03
      • 2020-09-19
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多