2017-09-11 6 views
1

私のアプリケーションがシリアルに受信バイトを処理していましたが、私は奇妙なバグに気付きました。時にはバイト(いつも0x03になる)が2倍処理されて、なぜかわからない。c#は同じシリアル受信バイトを2回処理することがあります

バイトを受信すると、+= ReadExisting()を使用して文字列に追加します。この文字列は私のバッファを形成します。バックグラウンドワーカーは、文字列が空になるまで文字列のすべてのバイトを処理します。文字列の最初の要素が読み込まれた後で削除されると、string.Length()はループサイクルごとに小さな数値を返します。

private void serial_DataReceived(object sender, SerialDataReceivedEventArgs e) 
     { 
      rxBuffer += serial.ReadExisting(); // adds new bytes to buffer 

      try { backgroundWorker1.RunWorkerAsync(); } catch { } // starts background worker if it is not working already. 
     } 


     private void backgroundWorker1_DoWork(object sender, System.ComponentModel.DoWorkEventArgs e) 
     { 
      while (rxBuffer.Length > 0) 
      { 
       byte b = Convert.ToByte(rxBuffer[0]); // reads in the next byte  
       rxBuffer = rxBuffer.Remove(0, 1); // deletes this byte from the string 

      // ... code ... does things do the UI and stuff 

ループ2xの間にいくつかのシリアルバイトが実行されることは確かです。私は自分の成果でそれを見てきました。いくつかの理由から、ダブルバイトは常に0x03です。 rxBufferは、プログラムのどこにでも触れていないことに注意してください。

Bullseye set at (0,2) 
2:05:10 << 0x80 
2:05:10 << 0x3 
2:05:10 << 0x13 
Bullseye set at (1,2) 
2:05:10 << 0x80 
2:05:10 << 0x3 
2:05:10 << 0x3 <--- this one should not be there. 
Bullseye set at (3,0) 
2:05:10 << 0x14 
2:05:10 << 0x80 
2:05:10 << 0x3 
2:05:10 << 0x15 
Bullseye set at (3,2) 
2:05:10 << 0x80 
2:05:10 << 0x3 
2:05:10 << 0x16 
Bullseye set at (4,2) 

なぜこの問題が発生し、どうすれば解決できますか?それは非同期のバイト読み取りとバックグラウンドワーカーに関係していますか?

+1

2つのスレッドでリソースを共有します。あなたは同期する必要があります。またはそれ以上:スレッドセーフバッファを使用します。 – Fildor

+0

削除を実行しているときに読み取りイベントが発生している可能性があります。イベントが発生すると、インラインコードに干渉しないことを確認する必要があります。 – jdweng

+0

これが本当にスレッディングの問題かどうかを調べるには、現在のスレッドIDとバッファの長さも出力してください。 – Fildor

答えて

1

迅速& 汚い修正について:

private readonly object _lock = new object(); 
private void serial_DataReceived(object sender, SerialDataReceivedEventArgs e) 
    { 
     lock(_lock) 
     { 
     rxBuffer += serial.ReadExisting(); // adds new bytes to buffer 
     } 
     try { backgroundWorker1.RunWorkerAsync(); } catch { } // starts background worker if it is not working already. 
    } 


    private void backgroundWorker1_DoWork(object sender, System.ComponentModel.DoWorkEventArgs e) 
    { 
     lock(_lock) 
     { 
     while (rxBuffer.Length > 0) 
     { 
      byte b = Convert.ToByte(rxBuffer[0]); // reads in the next byte  
      rxBuffer = rxBuffer.Remove(0, 1); // deletes this byte from the string 

     // ... code ... does things do the UI and stuff 
     } // end while 
     } // end lock 

より洗練されたソリューションは、あなたのクラスとあなたのコードに加えられた変更の詳細についての詳細情報が必要になります。

+0

Tnxうまくいくようです。私の解決策は、whileループ関数を呼び出してバックグラウンドワーカーを捨てることでした。私は「それほど悪くない」とは何か分からない – bask185

関連する問題