1

現在、フォームを閉じることに関連していると思われる問題が発生していますが、シリアル接続を介して接続されているスケールはデータを送信し続けます(1sekあたり約3パッケージ)。

DataReceived-Eventを介して新しいデータを処理します(データを照合しているだけなので、この問題の処理自体は面白くない可能性があります)COM_InUse変数とallowFireDataReceivedチェックに注意してください。):

    private void COMScale_DataReceived(object sender, EventArgs e)
    {
        if (allowFireDataReceived)
        {
            //set atomar state
            COM_InUse = true;

            //new scale:
            if (Properties.Settings.Default.ScaleId == 1)
            {
                strLine = COMScale.ReadTo(((char)0x2).ToString());
                //new scale:
                Regex reg = new Regex(Constants.regexScale2);
                Match m = reg.Match(strLine);
                if (m.Success)
                {
                    strGewicht = m.Groups[1].Value + m.Groups[2];
                    double dblComWeight;
                    double.TryParse(strGewicht, out dblComWeight);
                    dblScaleActiveWeight = dblComWeight / 10000;
                    //add comma separator and remove zeros
                    strGewicht = strGewicht.Substring(0, 1) + strGewicht.Substring(1, 2).TrimStart('0') + strGewicht.Substring(3);
                    strGewicht = strGewicht.Insert(strGewicht.Length - 4, ",");

                    //write to textbox
                    ThreadSafeSetActiveScaleText(strGewicht);

                    COMScale.DiscardInBuffer();
                    //MessageBox.Show(dblScaleActiveWeight.ToString(), "dblScaleActiveWeight");
                }

            }
            //free atomar state
            COM_InUse = false;
        }
    }

COM_InUse変数はグローバルブール値であり、データを処理する現在のプロセスがある場合は「通知」します。allowFireDataReceivedもグローバルブール値であり、falseに設定すると、送信されたデータを余分に処理することはありません。

私の問題は次のとおりです。

イベント処理は別のスレッドのようです。これは、イベントが処理された場合でもCOM_InUseがfalseに変わることはないため、キャンセルボタンのクリックでデッドロックが発生するようです(COM_InUseがfalseに設定されているCOMScale_DataReceivedの終わりを参照)。私が言ったように、allowFireDataReceived = falseを設定している間は完全に機能します(これ以上処理しません):whileループは終了しません。

    private void bScaleCancel_Click(object sender, EventArgs e)
    {
        allowFireDataReceived = false;
        while (COM_InUse)
        {
            ;
        }
        if (!COM_InUse)
        {
            ret = 1;
            SaveClose();
        }
    }

whileブロックをコメントアウトするときは、ボタンを2回クリックする必要がありますが、クラッシュすることなく機能します。これは非常にユーザーフレンドリーではないので、ウィンドウを安全に閉じるための別の方法を探しています。

情報:(COMデータが処理されたかどうかを確認せずに)単に閉じると、致命的なクラッシュが発生します。

したがって、誰かが私にこの問題の正確な原因を説明したり、これに対する解決策を提供したりできるかもしれません。(たぶん、キャンセルクリックイベントを再度トリガーすることになるでしょうが、それは非常に醜いです)

ご挨拶!

頼りにしています :)

//編集:これがの現在のコードです

    private void ThreadSafeSetActiveScaleText(string text)
    {
        // InvokeRequired required compares the thread ID of the
        // calling thread to the thread ID of the creating thread.
        // If these threads are different, it returns true.
        if (this.lScaleActive.InvokeRequired)
        {   
            SafeActiveScaleTextCallback d = new SafeActiveScaleTextCallback(ThreadSafeSetActiveScaleText);
            this.Invoke(d, new object[] { text });
        }
        else
        {
            this.lScaleActive.Text = text;
        }
    }
4

1 に答える 1

2
   ThreadSafeSetActiveScaleText(strGewicht);

はい、DataReceivedイベントはスレッドプールスレッドで実行されます。あなたはすでにそれを知っていました、そうでなければそれを「スレッドセーフ」と呼ぶことはなかったでしょう。私たちが見ることができないのは、このメソッドの中にあるものです。しかし、結果を考えると、Control.Invoke()を使用している可能性が高いです。

UIスレッドで実行されるコードでCOM_InUseをループすると、デッドロックが発生します。Control.Invoke()メソッドは、UIスレッドがデリゲートターゲットメソッドを実行した場合にのみ完了できます。ただし、UIスレッドは、アイドル状態のときにのみそれを実行でき、メッセージループをポンピングし、Windowsメッセージを待機します。そして、リクエストを呼び出します。Clickイベントハンドラー内でループしている間は、これを行うことはできません。したがって、Invoke()は完了できません。これにより、COM_InUse変数は常にtrueに設定されたままになります。これにより、Clickイベントハンドラーが永久にループします。デッドロック都市。

SerialPort.Close()メソッドを呼び出すと、まったく同じ問題が発生します。ポートは、すべてのイベントが処理された場合にのみ閉じることができます。

代わりにControl.BeginInvoke()を使用してこれを修正する必要があります。デリゲートターゲットの実行が開始されるまでに、データがまだ有効であることを確認してください。たとえば、必要に応じてコピーして、引数として渡します。

スケールが容赦なくデータを送信している間にフォームを閉じることは、一般的に問題です。破棄されたフォームで呼び出すと、例外が発生します。これを修正するには、FormClosingイベントハンドラーを実装し、e.Cancelをtrueに設定する必要があります。そして、DataReceivedイベントのサブスクライブを解除し、タイマーを開始します。間隔を数秒にします。タイマーが作動すると、フォームを再度閉じることができます。これで、すべてのデータが排出され、呼び出しが発生しなくなることが確認されます。

また、DiscardInBuffer()を呼び出すことは、データをランダムに失う場合にのみ有効であることに注意してください。

于 2012-06-03T15:47:19.893 に答える