6

当我将 Visual Studio 2010 配置从 Debug 更改为 Release 时,我得到了一个非常奇怪的行为:

我有一个BackgroundWorker: _bg,在DoWork我有:

                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我有一个MessageBox和用户交互之后,iswaiting将设置回false并且_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 运行它或在Debug模式下构建时,所有这些工作都非常好,但是当我将它构建到Release时,我永远不会退出while(iswaiting)循环,尽管我可以从日志中看到iswaiting已经设置回false.

编辑

更好的方法是非常受欢迎的!

4

3 回答 3

6

这可能是由于线程优化。为了安全地“看到”iswaiting释放模式的变化,您需要一个内存屏障。

“修复”此问题的最简单方法是将标记iswaitingvolatile

volatile bool iswaiting;

话虽如此,像这样“旋转”将完全消耗一个 CPU 内核。更好的方法是使用 aManualResetEvent表示您可以继续。

// 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并不是一个好主意。您有一个更根本的问题,因为您正在执行旋转等待,这实际上总是一个坏主意。您应该使用一种实际暂停线程直到它应该继续的方法。一种方法是使用 aManualResetEvent或 a Semaphore

查看您的代码,您正在等待用户关闭在进度更改事件中触发的消息框。我想说的是,您应该简单地将其包含在实际的“工作”事件中,而不是将其包含在进度更改事件中。doWork 方法最好在触发后不关心进度更改事件。

于 2012-10-17T16:20:05.297 回答
0

更好的方法是使用可以继续的信号量信号。

private Semaphore semaphore = new Semaphore(1, 1000);
semaphore.WaitOne();

在你想释放之后

semaphore.Release();
于 2020-04-18T14:31:10.167 回答