2011-01-12 4 views
1

サークル、メインフォームを最小化または移動したときにシリアルポートからデータを受信すると、

これはすでにどこかでカバーされています。私は検索して、私がすでに実装しているものを見つけます。

シリアルポート経由で接続されたデバイスからデータを受信するアプリケーションを開発しています。私はSerialPort datareceivedイベントを使用してデータをキャプチャしています。私はメインフォームのテキストボックスにデータを表示します。データは頻繁に受信されます。私はデバイスにコマンドを送信するためにTimerを使用しましたが、デバイスがデータを送信しました。タイマー間隔は100msです。 100ms間隔ごとに、いくつかのコマンドが送信され、それに対応してデータが受信される。私はTExtbox、ラベルなどのGUI要素を更新するためにInvoke関数を使用しました。すべての要素が美しく更新されています。しかし、フォームを移動する、フォームを最小化する、最大化する、またはどこかをクリックするなどのメインフォームの変更をデータ受信中に行うと、データ受信が停止します。私はなぜそれが起こったのか理由を見つけることができませんでしたか?私はまた、タイマー間隔を200,300,400,500に変更しましたが、同じ問題があります。

なぜそれが起こっているのか教えてください。そして、可能な解決策...事前に

おかげで.... :)

答えて

0

は、なぜあなたは別のスレッドで操作を行うと、表示されません。

+0

なぜでしょうか、serialport datareceivedイベントはセカンダリスレッドでも実行されます。 – Rahul

+0

UIに非同期のスレッドポストバックなどを作成する必要があります。 http://dotnetperls.com/backgroundworker – abmv

+0

これが唯一の方法です! – abmv

1

最小化するとタイマーが無効になるという問題があります。新しいThreadを作成し、Thread.Sleep(100);を使用してスリープ状態にする必要があります。また、閉じているときに中断します。次のようなものを考えてみてください。

Thread recieverThread = new Thread(delegate() 
    { 
    try 
    { 
     //try loading data 
     Thread.Sleep(100); 
    } 
    catch (ThreadAbortException) 
    { 
     //close port or something 
    } 
    }); 

//on form.close or something like that 
recieverThread.Abort(); 

これはすべきことです。また、別のスレッドで実行されているため、受信者更新インターフェイスの場合はForm.Invoke(...)を使用する必要があります。

+0

申し訳ありませんが、タイマーは無効になっていません。それは実行されていると私はコードにブレークポイントを置くことによってそれを観察した。 – Rahul

0

私の推測では、問題なくフォームコントロールを別のスレッドから更新できないため、タイマースレッドがクラッシュしていると思います。メインUIスレッドで実行するデリゲートを作成する必要があります。これは、Form.InvokeRequiredをテストし、それが真であればForm.Invokeを呼び出して行います。

何が起こっているのですか?タイマースレッドは、フォーム上のテキストボックスやその他のコントロールを更新しています。サイズを変更または最小化すると、フォームコントロールのハンドルが無効になります...もう使用できなくなります。あなたのタイマースレッドがまだ実行中で、それらを使用しようとしていることを除いて。クラッシュ!

マルチスレッド形式の良い例はhereです。重要な部分は次のとおりです。

delegate void SetBoolDelegate(bool parameter); 

// This would be your timer tick event handler... 
void SetInputEnabled(bool enabled) { 

    if(!InvokeRequired) { 
     button1.Enabled=enabled; 
     comboBoxDigits.Enabled=enabled; 
     numericUpDownDigits.Enabled=enabled; 
    } 
    else { 
     Invoke(new SetBoolDelegate(SetInputEnabled),new object[] {enabled}); 
    } 

} 

この例では、InvokeRequiredをテストします。 falseの場合は、メインのUIスレッドで実行しており、コントロールのプロパティを直接設定できます。 trueの場合は、Invoke()を呼び出し、メインのUIスレッドから呼び出される関数を渡します。

この例では、あなたが呼び出す関数/代理人は、あなたがいるのと同じ機能ですが、必ずしもそうである必要はありません。しかし、それをメインスレッド上で実行させるために、タイマーティックイベントハンドラを渡すことができます。

0

あなたのUIスレッドは、ウィンドウ移動操作中にモーダルループでブロックしています。その結果、Form.Invoke()もブロックを呼び出します。

データを受け取るバックグラウンドスレッドに加えて、キューを使用することをお勧めします。 UIスレッドは、タイマーイベント中にデータをポーリングするだけです。

競合状態を避けるために、キューアクセスを同期させる必要があります。 UIが複数の時間のかかる操作を行う必要があるため、UIスレッドが適用する更新セットを取得する必要がある場合は、キューインスタンスを交換します。

これが機能するように、キュー・マネージャの何か(両方のスレッドは、基本的にキューを所有し、管理者が周りにそれらを切り替え):

private Queue<T> dataQueue; 
private object syncLock = new Object(); 
private volatile bool dataAvailable; // Volatile to avoid locking on read. 

// Called by the background thread to add an event object (e.g. string) to the queue. 
void QueuePut(T data) 
{ 
    lock (this.syncLock) 
    { 
     if (this.dataQueue == null) 
     { 
      this.dataQueue = new Queue<T>(); 
     } 

     this.dataQueue.Add(data); 
     this.dataAvailable = true; 
    } 
} 

// Called by the UI thread to get the pending updates. 
Queue<T> QueueGet(Queue<T> oldQueue) 
{ 
    if (oldQueue != null) 
    { 
     oldQueue.Clear(); 
    } 

    Queue<T> result; 
    lock (this.syncLock) 
    { 
     result = this.dataQueue; 
     this.dataQueue = oldQueue; 
     this.dataAvailable = false; 
    } 

    return result; 
} 

// Called by UI thread to avoid retrieving an empty queue 
// (and subsequent reallocation). 
public bool IsDataAvailable() 
{ 
    get 
    { 
     return this.dataAvailable; 
    } 
} 

最小化したときにUIがまったく更新されませんこの方法です。また、古いイベントが害を受けずにパージされるようなロギングのようなものであれば、バックグラウンドキューの項目数に制限を設けることもできます(そうしないと、メモリ不足になる可能性があります)。

+0

あなたはUIスレッドがループ内でブロックしていると思いますか? –

関連する問題