0

私には3つSerialPortのコンポーネントがあり、そのうちの2DataReceivedつにはハンドラーがあります。データを受信すると、他のデータ(3番目のデータ)を介して出力を送信します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ハンドラーはスレッドプールで実行されます。それでも、一度に2つの読み取りを取得できることを意味します。

これを解決するには、ロックを使用できます。

OutputPortLockオブジェクトをクラスに追加します。

private object OutputPortLock = new object();

そして、出力ポートに書き込む前にロックしてみてください。

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

これにより、一度に1つのスレッドのみが出力ポートに書き込もうとします。他のプロセスがComPortを使用しようとすると、Com PortinUseエラーが発生する可能性があります。

于 2013-01-15T10:58:00.840 に答える
2

メソッドをロックする方法はいくつかありますsendToCOM。これにより、後続の呼び出しが最初の呼び出しが完了するまで待機するため、メソッドの2回の実行が停止します。別のプロセスが同じものを使用しようとした場合、これは役に立ちませんがSerialPort、ローカルの競合は停止します。

lock1つの方法は、次のようなオブジェクトでキーワードを使用することです。

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();
    }
}
于 2013-01-15T10:59:57.093 に答える
1

できることがいくつかあります。

1)ロック機構を構築します。スレッドは、このロックがロック解除されるまで待機してからメソッドにアクセスしようとします。つまり、各スレッドは順番にロックを解除して「sendToCOM」を起動します。

2)別の方法は、ConcurrentQueueを使用することです(http://msdn.microsoft.com/en-us/library/dd267265.aspxを参照)。これはスレッドセーフリストであり、必要に応じてCOMportオブジェクトも追加し、そこから起動できます。たとえば、そうすることについていくつか質問があります。

ConcurrentQueue<T>でスレッドを操作する方法

もっと多くの方法があると確信していますが、これらは私が頭のてっぺんから考えた2つです。2つ目は信頼性が高いと思いますが、実行するにはより多くの作業が必要になるため、1つ目が最大の関心事になる可能性があります。

于 2013-01-15T10:57:54.170 に答える