2

なぜこれが起こるのでしょうか?

スレッドを起動すると、クラスが実行されます。

そのクラスの中にはforループがあり、forループの中には「メッセージボックスへの書き込み」と別のクラスがあります。

書き込みとクラス(最初に発生するもの)を配置した魔女の順序がデータの精度に影響するのはなぜですか?

(これは、スレッドが実行されているクラス内にあります)

int atPDFNumber= 0
foreach (var z in q)
        {
                atPDFNumber++;

                convertToImage(z.FullName);

                txtboxtest.BeginInvoke(
            ((Action)(() => txtboxtest.Text += atPDFNumber.ToString())));
}

その出力は私にいくつかの重複する値を与えます。出力は

実行1:1 2 3 4 5 6 7 8 9 10 11 12 13 14

実行2:1 3 3 4 5 6 7 8 9 10 11 12 13 14

実行2:1 2 3 4 5 6 7 8 9 11 11 12 13 14

これがそれらすべてを正しい順序で実行する場所

foreach (var z in q)
            {
                    atPDFNumber++;

                txtboxtest.BeginInvoke(
                ((Action)(() => txtboxtest.Text += atPDFNumber.ToString())));

               convertToImage(z.FullName);

なぜそれが起こるのですか?ConvertToImageクラスで使用する外部メソッドもスレッドを実行している可能性があります。その場合、ConvertToImageが終了するのを待つためにスレッドを「一時停止」するにはどうすればよいですか...

そうでなければ、なぜこのスレッドがそのように動作するのかわかりませんか?

4

4 に答える 4

6

競合状態です。クロージャを作成します。

() => txtboxtest.Text += atPDFNumber.ToString()

内部的には、コンパイラは次のような匿名クラスを作成します。

class Closure
{
    public int? adPDFNumber;
    public void Call() {
        txtboxtest.Text += atPDFNumber.ToString();
    }
}

そしてそれを使用します:

var closure = new Closure();
closure.atPDFNumber = atPDFNumber;
txtboxtest.BeginInvoke(closure.Call);

BeginInvokeは実際にGUIスレッドでメソッドCallを呼び出し、それが発生した場合、変数atPDFNumberはすでにインクリメントされている可能性があります。クロージャーで一時変数を渡す必要があります。

 var tmp = atPDFNumber++;
 txtboxtest.BeginInvoke(() => txtboxtest.Text += tmp.ToString());

更新: この紛らわしい動作は、最新バージョンのC#言語で変更されました。C#5では、ラムダでループ変数を安全に使用でき、コードサンプルは問題なく機能します。

于 2012-10-05T08:56:16.630 に答える
4

アクションは、atPDFNumber変数の現在の値ではなく、その値をキャプチャしています。あなたの例では、atPDFNumberをローカル変数に割り当て、それをアクションに渡すと、期待どおりに機能します。

int atPDFNumber = 0; 
foreach (var z in q)
{
    atPDFNumber++; 
    convertToImage(z.FullName);
    int currentValue = atPDFNumber;
    txtboxtest.BeginInvoke(((Action)(() => txtboxtest.Text += currentValue.ToString())));
}

ここでは、C#での変数キャプチャについて見つけることができます

于 2012-10-05T08:51:52.297 に答える
1

2番目のサンプルには、最初のサンプルと同じ問題がありますが、処理の場所が原因で問題が少なくなります。txtboxtest.Text + = atPDFNumber.ToString()がいつ実行されるか、および実行時にスレッドが中断されないかどうかを制御することはできません。より大きなテストセットを作成すると、実行2および3と同じ結果が表示されるという大きな変化があります。

表示される問題は、競合状態と呼ばれます。デリゲートスレッドを安全にする必要があります。

于 2012-10-05T08:56:46.080 に答える
0

他のスレッドを待機する場合は、 Thread.Join()メソッドを使用できます。

しかし、問題はクロージャだと思います。クロージャについてもっと読んでください。

于 2012-10-05T08:54:59.517 に答える