【发布时间】:2015-01-28 17:16:37
【问题描述】:
我以前从未见过这样的事情。我正在使用 Visual Studio 2015 预览版并在 Visual Studio 2012 上对其进行了验证。
private void InitializeBackgroundWorkers()
{
MONITOR.WorkerReportsProgress = true;
MONITOR.WorkerSupportsCancellation = true;
MONITOR.DoWork += new DoWorkEventHandler(MONITOR_DoWork);
MONITOR.ProgressChanged += new ProgressChangedEventHandler(MONITOR_ProgressChanged);
MONITOR.RunWorkerCompleted += new RunWorkerCompletedEventHandler(MONITOR_WorkCompleted);
MONITOR2.WorkerReportsProgress = true;
MONITOR2.WorkerSupportsCancellation = true;
MONITOR2.DoWork += new DoWorkEventHandler(MONITOR2_DoWork);
MONITOR2.ProgressChanged += new ProgressChangedEventHandler(MONITOR2_ProgressChanged);
}
问题出现在 BackgroundWorker 的 DoWork 事件中。显然我犯了一个错误。
private void MONITOR2_DoWork(object sender, DoWorkEventArgs e)
{
while (CONTINUE)
{
oldClockNow = clockNow;
//BP1
clockThen = RunTime.ElapsedTicks;
Thread.Sleep(1000);
//BP2
clockNow = RunTime.ElapsedTicks;
TS = RunTime.Elapsed;
MONITOR2.ReportProgress(0);
}
RunTime.Stop();
}
问题是由于各种原因,我注意到 ClockThen 总是比 ClockNow“更新”。直到现在我都忽略了它,并更改了我的代码以将 ClockThen 用作 ClockNow,反之亦然。
我终于有时间仔细查看带有断点的代码。我将一个放在 clockThen 分配,一个放在 clockNow 分配,一个放在 ReportProgress 事件中,所以我可以在 MONITOR2 堆栈之外再停止一次。
注意:我使用 ProgressChanged 作为更新主 UI 的一种方式。
private void MONITOR2_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
double calcClockOld = (((double)oldClockNow) * (1F / Stopwatch.Frequency));
double calcClockThen = (((double)clockThen) * (1F / Stopwatch.Frequency));
double calcClockNow = (((double)clockNow) * (1F / Stopwatch.Frequency));
//BP3
tbxClockDrift.Text = ((calcClockThen - calcClockNow) * 1000000).ToString("0.#####\\ µs");
string timestamp = String.Format("{0:00}:{1:00}:{2:00}", TS.Hours, TS.Minutes, TS.Seconds);
tbxTime.Text = DateTime.Now.ToShortDateString() + " " + DateTime.Now.ToLongTimeString();
tbxRunTime.Text = timestamp;
tbxTimeZone.Text = TimeZone.CurrentTimeZone.ToUniversalTime(DateTime.Now).ToString();
}
第三个断点在 tbxClockDrift.Text 赋值处。
所以我总共有 3 个断点,但是当单步执行代码时,BP1 总是执行两次,我相信这就是为什么值不断变高的原因!
所以这一步我看到了一个幻像断点:
Step Through 1,clockThen = RunTime.ElapsedTicks;
Step through 2,跳转到clockNow = Runtime.ElapsedTicks;睡了一秒钟后。
逐步完成 3,回到时钟然后分配(验证新值!)
Step through 4,tbxClockDrift.Text 赋值!
为什么clockThen收到了第二个任务!?
【问题讨论】:
-
你是如何设置BackgroundWorker的?
-
听起来你有不止一个后台工作人员在运行,当你跳过 Sleep 调用时,调试器会在两者之间切换。
-
您的代码不是线程安全的,ProgressChanged 事件处理程序在您的工作人员调用 ReportProgress() 之后 运行任意时间。这意味着您的事件处理程序不能使用 clockThen/Now 变量。它不必使用 ReportProgress(int, object) 重载,而是允许您将值传递给事件处理程序。
-
添加了 BackgroundWorker 初始化代码。 @Hans 等等,你的意思是 ReportProgress() 没有按顺序处理?我认为我的代码逻辑本质上是线程安全的,因为这些变量仅在 ReportProcess() 启动后才被读取,这意味着当时它们没有被访问。如果是这样,那将是我的错误。
标签: c# .net multithreading backgroundworker