0

アプリを閉じても、アプリがまだ機能しているのはなぜですか。
シリアルポートからのデータの読み取りが原因だと思います。

シリアルポート番号はComboBoxから選択されます。
シリアルポートからのデータに応じて、関数WriteDataはチェックボックスを更新します。
抜粋は次のとおりです。

    // Choosing of communication port from ComboBox
    private void comboBoxCommunication_SelectionChanged(object sender, SelectionChangedEventArgs e)
    {
        if (serialPort.IsOpen)
        {
            serialPort.DataReceived -= new System.IO.Ports.SerialDataReceivedEventHandler(Recieve);
            serialPort.Close();
        }
        try
        {
            ComboBoxItem cbi = (ComboBoxItem)comboBoxKomunikacia.SelectedItem;
            portCommunication = cbi.Content.ToString();
            serialPort.PortName = portCommunication;
            serialPort.DataReceived += new System.IO.Ports.SerialDataReceivedEventHandler(Recieve);
            serialPort.BaudRate = 2400;
            serialPort.Open();
            serialPort.DiscardInBuffer();
        }
        catch (IOException ex)
        {
            MessageBox.Show(ex.ToString(), "Error!", MessageBoxButton.OK, MessageBoxImage.Error);
        }
    }

    // Close the window
    private void Window_Closed(object sender, EventArgs e)
    {
        if (serialPort.IsOpen)
        {                
            serialPort.DataReceived -= new System.IO.Ports.SerialDataReceivedEventHandler(Recieve);                
            serialPort.Close();
        }
    }

    // Data reading
    private delegate void UpdateUiTextDelegate(char text);
    private void Recieve(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
    {
        if (serialPort.IsOpen)
        {
            try
            {
                serialPort.DiscardInBuffer();
                char c = (char)serialPort.ReadChar();
                Dispatcher.Invoke(DispatcherPriority.Send,
                    new UpdateUiTextDelegate(WriteData), c);                    
            }
            catch(IOException ex)
            {
                MessageBox.Show(ex.ToString(), "Error!", MessageBoxButton.OK, MessageBoxImage.Error);
            }
        }
    }

    // Update of checkboxes
    private void WriteData(char c) { ... }
4

1 に答える 1

3

コードがデッドロックを引き起こし、Close()呼び出しでプログラムをブロックする可能性が非常に高くなります。問題のステートメントは、Dispatcher.Invoke()呼び出しです。その呼び出しは、UIスレッドが呼び出しをディスパッチするまで完了できません。デッドロックは、Close()を呼び出すと同時に、DataReceivedイベントの実行がビジー状態になると発生します。イベントが実行されているため、Close()呼び出しを完了できません。UIスレッドがアイドル状態ではないためにInvoke()を完了できないため、イベントハンドラーを完了できず、Close()呼び出しでスタックします。デッドロック都市。

これは、バグがあるため、コードで特に発生する可能性があります。DataReceivedでDiscardInBuffer()を呼び出します。これにより、受信したデータが破棄されるため、次のReadChar()呼び出しはしばらくブロックされ、さ​​らにデータが受信されるのを待ちます。デバイスが何も送信しなくなった場合は、おそらく永久にブロックされます。

DiscardInBuffer()呼び出しを削除し、代わりにDispatcher.BeginInvoke()を使用して、この問題を修正してください。

于 2012-04-08T13:23:18.340 に答える