【问题标题】:How to synchronize SerialPort operations?如何同步 SerialPort 操作?
【发布时间】:2016-05-28 18:04:05
【问题描述】:

我有一个通过串行端口与微控制器通信的应用程序。我想在后台工作人员中定期检查控制器的状态,并允许用户通过发送命令和接收响应来异步(通过用户界面)与控制器交互。

UI 和 Background Worker 使用 SerialCommunication 静态类:

static class SerialCommunication
{
    static SerialPort serialPort;
    static int readWriteTimeout = 1000; // [ms]
    static int waitForTransmissionTimeout = 2; // [s]
    static string rxData = "", endOfString = "" + char.MinValue;
    static bool WaitingForSerialData = false; // Set in SerialWrite(), cleared in SerialRead()

    [...]
    public static string SerialRead()
    {
        try
        {
            rxData = serialPort.ReadTo(endOfString);
        }
        catch (TimeoutException)
        {
            WaitingForSerialData = false;
            throw new Exception(Properties.Resources.serial_read_timeout);
        }
        WaitingForSerialData = false;
        return rxData;
    }

    public static void SerialWrite(string text)
    {
        DateTime start = DateTime.Now;
        while (WaitingForSerialData) // Avoids the situation in which a command executed on a thread receives the response for the command executed from a different thread
        {
            if (!WaitingForSerialData)
            {
                try
                {
                    WaitingForSerialData = true; // All commands wait for confirmation/data, so it is normal to set this boolean value for every serial transmission
                    serialPort.Write(text);
                }
                catch (TimeoutException)
                {
                    throw new Exception(Properties.Resources.serial_write_timeout);
                }
            }
            else
            {
                System.Threading.Thread.Sleep(100);
                if ((DateTime.Now - start).Seconds >= waitForTransmissionTimeout)
                {
                    throw new Exception("Timeout");
                }
            }
        }
    }
}

串口在应用程序启动时初始化。 SerialWriteSerialRead 在 UI 或 Background Worker 中连续调用。

我想避免命令接收来自在不同线程中执行的另一个命令的响应的情况。目前,我已经在发送命令之前在 SerialWrite 中等待接收命令(以便 SerialRead 完成),但如果 SerialWrite 是,我担心这会阻塞 UI(最多 waitForTransmissionTimeout 秒)从那里执行。

那么同步 SerialPort 操作的最佳方式是什么?

【问题讨论】:

  • 那么,所有命令都是 SerialWrite 后跟 SerialRead 来接收响应?如果是这样,为什么不在单个 SendCommand 或其他东西中结合读取和写入操作?
  • @Evk 但是如果 SendCommand 被执行会发生什么,例如,在后台工作线程中,以及在 UI 中执行之后(完成执行之前)?
  • 你应该用简单的锁来保护整个操作(写+读)。然后,如果 UI 在后台工作人员完成执行之前发送命令 - 它会等到它完成。当然,无论如何您都不应该从 UI 线程执行该操作。从后台线程执行它,然后在完成后将结果分派回 UI 线程(向用户显示结果)。永远不要直接在 UI 线程上执行这样的事情。
  • @Evk 你能给出一个代码示例吗?

标签: c# wpf multithreading serial-port synchronization


【解决方案1】:

我不知道整个情况,但在我看来你可以使用一个简单的锁来序列化你的写然后读,就像这样:

static class SerialCommunication
{
    static SerialPort serialPort;
    static string endOfString = "" + char.MinValue;
    static readonly object _commandLock = new object();

    public static string SendCommand(string text) {
        lock (_commandLock) {
            SerialWrite(text);
            return SerialRead();
        }
    }

    private static string SerialRead() {
        try {
            return serialPort.ReadTo(endOfString);
        }
        catch (TimeoutException) {
            throw new Exception(Properties.Resources.serial_read_timeout);
        }            
    }

    private static void SerialWrite(string text) {
        try {
            serialPort.Write(text);
        }
        catch (TimeoutException) {
            throw new Exception(Properties.Resources.serial_write_timeout);
        }
    }
}

【讨论】:

  • 谢谢!关于 UI,我应该使用 Background Worker 进行串行操作,还是有解决方案可以编写更紧凑的代码?
  • 如果您的 C# 编译器版本支持,您可以使用后台线程,或使用 Task.Run,​​或使用 async\await。你可以在很多地方读到这个——例如stephenhaunts.com/2014/10/14/…
  • 我已经测试了这个方法并且得到了以下异常: I/O 操作由于线程退出或应用程序请求而被中止。我有一个后台工作人员,每 2 秒检查一次系统的状态,用户可以从 GUI 命令系统。当用户发出命令(也在后台工作程序中执行)时,有时会出现错误。 为什么lock方法不起作用?
  • @CristianM 我真的怀疑这个错误与您提供的代码有关。也许您必须提出新问题并发布到目前为止的代码,以及异常堆栈跟踪等。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-12-29
  • 1970-01-01
  • 1970-01-01
  • 2017-09-09
相关资源
最近更新 更多