Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/273.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 使用BackgroundWorker和Thread.Sleep的奇怪行为_C#_.net_Multithreading_Backgroundworker - Fatal编程技术网

C# 使用BackgroundWorker和Thread.Sleep的奇怪行为

C# 使用BackgroundWorker和Thread.Sleep的奇怪行为,c#,.net,multithreading,backgroundworker,C#,.net,Multithreading,Backgroundworker,我以前从未见过这样的事。我正在使用Visual Studio 2015预览版,并在Visual Studio 2012上进行了验证 private void InitializeBackgroundWorkers() { MONITOR.WorkerReportsProgress = true; MONITOR.WorkerSupportsCancellation = true; MONITOR.DoWork += new DoWo

我以前从未见过这样的事。我正在使用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分配,另一个放置在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总是执行两次,我相信这就是为什么值一直较高的原因

因此,我将这一步视为幻象断点:

步骤1,clockThen=RunTime.ElapsedTicks

步骤2,跳到clockNow=Runtime.ElapsedTicks;睡了一会儿之后

第3步,返回时钟然后分配(验证新值!)

第四步,tbxClockDrift.文本分配


为什么他会收到第二份任务

如果我稍微重写一下您的方法,使睡眠成为while循环中发生的最后一件事,那么问题就更明显了。此代码的行为与当前代码完全相同

private void MONITOR2_DoWork(object sender, DoWorkEventArgs e)
{
    if(CONTINUE)
    {
        oldClockNow = clockNow;
        //BP1
        clockThen = RunTime.ElapsedTicks;
        Thread.Sleep(1000);
        while (true)
        {
            //BP2
            clockNow = RunTime.ElapsedTicks;

            TS = RunTime.Elapsed;

            MONITOR2.ReportProgress(0);
            if(!CONTINUE)
                break;

            oldClockNow = clockNow;
            //BP1
            clockThen = RunTime.ElapsedTicks;
            Thread.Sleep(1000);
        }
    }
    RunTime.Stop();
}
因此,
clockThen
没有收到第二个任务,它只是
clockThen
是你睡觉前做的最后一件事。另外,
ReportProgress
的处理也不一定要在调用函数的时候进行,调用函数只是将事件排成队列,以便在用户界面下一次处理该事件时触发


因此,现在发生的是分配
clockNow
,将进度报告排队,为
clockThen
分配一个值,最后开始睡眠。当你睡觉时,
ReportProgress
终于开始运行了,你得到了睡前分配的
clockThen
的值。

你是如何设置BackgroundWorker的?听起来好像你有多个后台工作程序在运行,当你一步一步的时候,调试器会在这两个后台工作程序之间切换您的代码不是线程安全的,ProgressChanged事件处理程序在工作程序调用ReportProgress()后运行任意时间。这意味着您的事件处理程序不能使用clockThen/Now变量。不必使用ReportProgress(int,object)重载,它允许您将值传递给事件处理程序。添加了BackgroundWorker初始化代码@Hans等等,你是说ReportProgress()没有按顺序处理?我认为,我的代码的逻辑本质上是线程安全的,因为这些变量只有在ReportProcess()启动后才被读取,这意味着它们当时没有被访问。如果是这样的话,那就是我的错误。这是可行的,但正如Hans Passant所说,它不一定是线程安全的,也不一定是按受控顺序执行的。我认为BackgroundWorker\u DoWork在BackgroundWorker\u ReportProgress执行、完成并返回DoWork部分时暂时暂停。显然情况并非如此;DoWork继续异步执行。它继续运行它的无限循环,这解释了为什么分配顺序很快失控。没有虚断点,循环在到达/执行ReportProgress函数之前刚刚开始。@RagingCain我的答案中没有任何问题,我只是解释出了什么问题,你可以随心所欲地解决问题。@ScottChamerlain对此表示抱歉,我以前读过它时有点匆忙。我感谢你提供的额外信息。