Bol*_*olu 6 c# release backgroundworker visual-studio-2010 while-loop
当我将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.)
Run Code Online (Sandbox Code Playgroud)
在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());
}
Run Code Online (Sandbox Code Playgroud)
所有这些作品非常好,当我从Visual Studio运行或建造中调试模式,但是当我建立它松开,我从来没有走出的while(iswaiting)循环,但我可以看到该日志iswaiting已被设置回false.
编辑:
更好的方式是非常欢迎!
这可能是由于线程优化造成的.为了安全地"看到" iswaiting发布模式中的更改,您需要一个内存屏障.
"修复"这个的最简单方法是标记iswaiting为volatile:
volatile bool iswaiting;
Run Code Online (Sandbox Code Playgroud)
话虽如此,像这样"旋转"将完全消耗一个CPU核心.一个更好的方法是用a ManualResetEvent来表示你可以继续.
// Add:
private ManualResetEvent allowProgress = new ManualResetEvent(false);
Run Code Online (Sandbox Code Playgroud)
然后,你不会使用等待,而是:
_bg.ReportProgress(1, filePath);
allowProgress.WaitOne(); // This will block until it's set
Run Code Online (Sandbox Code Playgroud)
要允许此操作继续,请使用:
result = Microsoft.Windows.Controls.MessageBox.Show("Question" ,"Title", MessageBoxButton.YesNoCancel, MessageBoxImage.Warning);
allowProgress.Set();
Run Code Online (Sandbox Code Playgroud)
这里的优点是,在您被阻止时不会消耗CPU,并且您不必担心自己的内存障碍.
所以你的问题可能是你使用的是布尔字段,而你没有将其标记为volatile.正因为如此,某些优化(通常只在释放模式中应用)可以导致两个线程访问是本地它们的线程(可能在他们的处理器的核的高速缓存,例如)的场的拷贝.
但是,在volatile这里标记这个领域并不是一个好主意.你有一个更基本的问题,你正在执行一个spinwait,这实际上总是一个坏主意.您应该使用实际暂停线程的方法,直到它应该继续.一种方法是使用a ManualResetEvent或a Semaphore.
查看您的代码,您正在等待的是用户解除在progress progress事件中触发的消息框.我想说的是,你应该将它包含在实际的"do work"事件中,而不是在进度改变事件中使用它.doWork方法一旦被触发就不需要关心进度改变事件.
| 归档时间: |
|
| 查看次数: |
1161 次 |
| 最近记录: |