发布和调试之间的区别?

时间:2012-10-17 16:16:42

标签: c# visual-studio-2010 while-loop backgroundworker release

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

我在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中的

我有一个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

修改

这样做的好方法非常受欢迎!!

3 个答案:

答案 0 :(得分:6)

这可能是由于线程优化造成的。为了在发布模式下安全地“看到”iswaiting中的更改,您需要一个内存屏障。

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

volatile bool iswaiting;

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

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

然后,你不会使用等待,而是:

_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,而且你不必担心自己的内存障碍。

答案 1 :(得分:5)

因此,您的问题可能是您使用的是布尔字段,并且您还没有将其标记为volatile。因此,某些优化(通常仅在发布模式下应用)可能导致两个线程访问其线程本地的字段副本(例如,可能在其处理器核心的高速缓存中)。

但是,在这里标记字段volatile并不是一个好主意。你有一个更基本的问题,你正在执行一个spinwait,这实际上总是一个坏主意。您应该使用实际暂停线程的方法,直到它应该继续。一种方法是使用ManualResetEventSemaphore

查看您的代码,您正在等待的是用户解除在进度更改事件中触发的消息框。我想说的是,你应该把它简单地包含在实际的“工作中”中,而不是在改进过程中将它包含在内。事件。一旦它被触发,doWork方法就不需要关心进度改变事件。

答案 2 :(得分:0)

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

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

以及您要释放后

semaphore.Release();