【问题标题】:Threading - Multiple SerialPort and one DataGridView线程 - 多个 SerialPort 和一个 DataGridView
【发布时间】:2013-01-15 10:53:09
【问题描述】:

我有 3 个 SerialPort 组件,其中 2 个有 DataReceived 处理程序。 当接收到数据时,它们正在通过其他SerialPort 发送输出 (第三个)。 我知道在我的应用程序中SerialPorts 将尝试同时发送的可能性并不高,但我尝试模拟这一点,当然我得到了一个错误,即COM PORT 正在使用。

private void sendToCOM(String comNumber, String msg, String speed)
    {
        try
        {
            using (SerialPort comPort = new SerialPort(comNumber, Int32.Parse(speed), Parity.None, 8, StopBits.One))
            {
                comPort.Open();
                comPort.Write(msg);
                comPort.Close();
                comPort.Dispose();
            }
        }
        catch(Exception ex)
        {
                cstFuncs.errorHandler(ex.Message, SettingsForm);
        }
    }

我知道每个SerialPort 都有自己的线程。

如何创建队列或如何防止两个串行端口尝试同时访问相同的资源(并且不会丢失应该发送出去的数据)

【问题讨论】:

    标签: c# multithreading event-handling serial-port queue


    【解决方案1】:

    有几种方法可以锁定sendToCOM 方法。这将通过导致任何后续调用等待第一次完成来停止该方法执行两次。如果另一个进程尝试使用相同的SerialPort,这将无济于事,但它会阻止任何本地争用。

    一种方法是在对象上使用lock 关键字,如下所示:

    private readonly object _myLock = new object();
    
    private void sendToCOM(String comNumber, String msg, String speed)
    {
        try
        {
            lock(_myLock)
            {
                using (SerialPort comPort = new SerialPort(comNumber, Int32.Parse(speed), Parity.None, 8, StopBits.One))
                {
                    comPort.Open();
                    comPort.Write(msg);
                    comPort.Close();
                    comPort.Dispose();
                }
            }
        }
        catch(Exception ex)
        {
            cstFuncs.errorHandler(ex.Message, SettingsForm);
        }
    }
    

    另一种方法是使用ManualResetEventSlim(或类似的东西)来达到相同的效果:

    private ManualResetEventSlim _myLock = new ManualResetEventSlim(true);
    
    private void sendToCOM(String comNumber, String msg, String speed)
    {
        _myLock.Wait();
        try
        {
            _myLock.Reset();
            using (SerialPort comPort = new SerialPort(comNumber, Int32.Parse(speed), Parity.None, 8, StopBits.One))
            {
                // ..
            }
        }
        catch(Exception ex)
        {
            cstFuncs.errorHandler(ex.Message, SettingsForm);
        } 
        finally
        {
            _myLock.Set();
        }
    }
    

    【讨论】:

    • 感谢您的帮助。这两种方法有什么区别?我尝试了第二种方法,它看起来很有效,但我设法让它崩溃了一次(我有 2 个应用程序,每 100 毫秒将字符串发送到每个 com 端口)
    • 真正的区别只是用法。老实说,我建议使用lockManualResetEventSlim 只是我在玩弄的一个想法,它应该仍然有效。您确定崩溃是由这种方法引起的吗?
    • 应用程序没有崩溃(“catch”捕获它)并且异常是 Access to the port 'COM6' is denied. 。在我尝试植入这种锁定(第二种方法)之前,我得到了很多。现在我得到的错误少了很多,但我仍然得到一些..我现在要尝试第一种方法。
    • 这当然很奇怪。老实说,我根本没有与SerialPorts 合作过,所以我无法就此提供更可靠的建议。但是,我知道这很糟糕,但是在开头或finally 中人为诱导的延迟可能会有所帮助? (谈Thread.Sleep
    • 我现在尝试了第一种方法,它减慢了所有过程(但我现在没有收到任何错误)也许正如你所建议的,稍微延迟一下并使用第二种方法应该可以解决问题。实际上我真的不需要这么高的速度,但是如果有一天需要的话,我能最大限度地利用它会很好。
    【解决方案2】:

    您可能没有每个串行端口的线程,而是在线程池中执行 DataReceived 处理程序。这仍然意味着您可以一次读取两次。

    您可以使用锁定来解决这个问题:

    在你的类中添加一个 OutputPortLock 对象:

    private object OutputPortLock = new object();
    

    并在写入输出端口之前尝试锁定它:

    lock(OutputPortLock)
    {
        using(SerialPort comPort=....)
        {
            ... write to com port ...
        }
    }
    

    这将确保一次只有一个线程尝试写入输出端口。如果其他进程尝试使用 Com Port in Use,您可能仍会收到错误。

    【讨论】:

    • 非常感谢您的帮助。看起来就是这样..我将阅读更多关于它的内容。
    【解决方案3】:

    你可以做一些事情;

    1) 建立锁机制。线程在尝试访问该方法之前将等待直到该锁被解锁,这意味着每个线程将依次触发“sendToCOM”

    2) 另一种方法是使用 ConcurrentQueue(请参阅:http://msdn.microsoft.com/en-us/library/dd267265.aspx)。这是一个线程安全列表,如果需要,您也可以添加 COMport 对象,然后从那里触发它们。例如,关于这样做有几个问题;

    How to work threading with ConcurrentQueue<T>

    我确信还有更多方法,但这些是我想到的 2。我会说第二个更可靠,但需要更多的工作才能运行,所以第一个可能是您的最佳利益。

    【讨论】:

      猜你喜欢
      • 2013-11-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-06-30
      • 2015-10-22
      • 1970-01-01
      • 1970-01-01
      • 2020-10-04
      相关资源
      最近更新 更多