0

我有 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人都有自己的线程。

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

4

3 回答 3

2

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

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

将 OutputPortLock 对象添加到您的类:

private object OutputPortLock = new object();

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

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

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

于 2013-01-15T10:58:00.840 回答
2

有几种方法可以锁定该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);
    }
}

另一种方法可能是使用 a 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();
    }
}
于 2013-01-15T10:59:57.093 回答
1

您可以做一些事情;

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

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

如何使用 ConcurrentQueue<T> 处理线程

我敢肯定还有更多的方法,但这些是我想到的 2。我会说第二个更可靠,但需要更多的工作才能运行,所以第一个可能是你最感兴趣的。

于 2013-01-15T10:57:54.170 回答