6

Visual Studio 2010の構成をデバッグからリリースに変更すると、非常に奇妙な動作が発生します。

私はBackgroundWorker:を持っています_bgDoWork私は持っています:

                iswaiting = true;
                _bg.ReportProgress(1, filePath);
                while (iswaiting)
                {                        
                  ;
                }
                //My other part of code (EDIT: something do to with the `result` I get from the user.)

ProgressChanged私はaを持っておりMessageBox、ユーザーとの対話の後、iswaitingfalseに戻され、_bg DoWorkプログラムは続行されます。

 void _bg_ProgressChanged(object sender, ProgressChangedEventArgs e)
    {
        //my other part of code........
       result = Microsoft.Windows.Controls.MessageBox.Show("Question" ,"Title", MessageBoxButton.YesNoCancel, MessageBoxImage.Warning);

       iswaiting=false; 
       log(iswaiting.toString());                  
    }

これらはすべて、Visual Studioから実行するか、デバッグモードでビルドすると非常にうまく機能しますが、リリースにビルドすると、ログからはすでにに設定されてwhile(iswaiting)いることがわかりますが、ループから抜け出すことはありません。iswaitingfalse

編集

これを行うためのより良い方法は大歓迎です!!

4

3 に答える 3

6

これは、スレッドの最適化が原因である可能性があります。リリース モードでの変更を安全に「見る」ためにはiswaiting、メモリ バリアを配置する必要があります。

これを「修正」する最も簡単な方法は、次のようにマークすることiswaitingですvolatile

volatile bool iswaiting;

そうは言っても、このように「回転」すると、1 つの CPU コアが完全に消費されます。より良いアプローチは、 a を使用して、ManualResetEvent続行できることを知らせることです。

// Add:
private ManualResetEvent allowProgress = new ManualResetEvent(false);

次に、iswaiting を使用する代わりに、次のようにします。

_bg.ReportProgress(1, filePath);
allowProgress.WaitOne(); // This will block until it's set

これを継続するには、次を使用します。

 result = Microsoft.Windows.Controls.MessageBox.Show("Question" ,"Title", MessageBoxButton.YesNoCancel, MessageBoxImage.Warning);

  allowProgress.Set();

ここでの利点は、ブロックされている間は CPU を消費しないことと、メモリ バリアについて自分で心配する必要がないことです。

于 2012-10-17T16:19:25.407 に答える
5

したがって、問題はブールフィールドを使用している可能性が高く、それを としてマークしていませんvolatile。このため、特定の最適化 (リリース モードでのみ適用されることが多い) により、両方のスレッドが、スレッドに対してローカルなフィールドのコピーにアクセスする可能性があります (たとえば、プロセッサのコアのキャッシュ上にある可能性があります)。

ただし、フィールドをマークすることvolatileは、ここではあまり良い考えではありません。スピンウェイトを実行しているという点で、より根本的な問題がありますが、これは事実上常に悪い考えです。スレッドが続行されるまで実際にスレッドを一時停止する方法を使用する必要があります。1 つの方法は、ManualResetEventまたはを使用することSemaphoreです。

コードを見ると、進行状況の変更イベントで発生したメッセージ ボックスをユーザーが閉じるのを待っています。これを進行状況の変更イベントに含めるのではなく、実際の「作業を行う」イベントに含めるだけでよいと思います。doWork メソッドは、起動後に進行状況の変更イベントを気にしないことが望ましいです。

于 2012-10-17T16:20:05.297 に答える