You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C# BackgroundWorker的DoWork循环未完成提前退出问题

Ping检测程序循环随机提前终止问题

我开发了一款Ping检测程序,核心运行逻辑为:遍历共8个Ping对象逐个发送Ping请求,等待1000ms后重复执行上述流程,总循环次数由用户输入的运行秒数决定。

当设置程序运行时长为2-3秒时,循环运行完全符合预期,每个Ping对象的成功Ping计数准确无误;但将运行时长设置为10秒(即循环计数变量count=10)时,循环通常在执行到计数变量i=6左右就会意外终止,直接触发RunWorkerCompleted事件,实际循环执行次数完全随机。

我最初怀疑是线程相关故障,曾尝试移除wait方法中的Application.DoEvents()逻辑排查干扰,但问题仍存在:设置count=10进行两次测试,第一次仅执行1次循环就退出,第二次执行7次循环后退出。

相关实现代码

BackgroundWorker的DoWork事件处理方法

private async void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
    try
    {
        // Create background worker 
        BackgroundWorker worker = (BackgroundWorker)sender;

        // Write to log file
        await file.WriteAsync("Starting job...\n");
        await file.WriteAsync("Requested amount of pings: " + count + "\n");
        // Create date object for logs
        DateTime localDate = DateTime.Now;

        for (int i = 0; i < count; i++)
        {
            // Create ping objects
            System.Net.NetworkInformation.Ping pinger = new System.Net.NetworkInformation.Ping();
            PingReply pingReply;

            foreach (Ping pingObj in pings)
            {
                try
                {
                    pingReply = pinger.Send(pingObj.IpAddress);
                    // Write log file
                    await file.WriteLineAsync(localDate.TimeOfDay + " | Friendly Name " + pingObj.FriendlyName + " | Ping: " + pingReply.Address + " | Status " + pingReply.Status + " | Time: " + pingReply.RoundtripTime);
                    if (pingReply.Status.ToString().Contains("Success"))
                    {
                        pingObj.SuccessfulPings += 1;
                    }
                    else // Unsuccessful ping has been sent
                    {
                        pingObj.FailedPings += 1;
                    }
                }
                catch (Exception ex)
                {
                    Debug.WriteLine(ex.ToString());
                }
            }
            wait(1000);
        }
    }
    catch (Exception a)
    {
        Debug.WriteLine(a.ToString());
    }
}

按钮点击启动BackgroundWorker的事件处理方法

private void Ping_Btn_Click(object sender, EventArgs e)
{
    int counter = 1;
    if (backgroundWorker1.IsBusy != true)
    {
        // For every ping object    
        foreach (Ping pinger in pings)
        {
            // Set the appropriate UI element properties
            // Create initial control object
            // Finds controls in which their name matches the string
            Control? ctl = this.Controls.Find("greenBox" + counter, true).FirstOrDefault() as Control;
            if (ctl != null)
            {
                ctl.Visible = false;
            }
            ctl = this.Controls.Find("orangeBox" + counter, true).FirstOrDefault() as Control;
            if (ctl != null)
            {
                ctl.Visible = false;
            }
            ctl = this.Controls.Find("redBox" + counter, true).FirstOrDefault() as Control;
            if (ctl != null)
            {
                ctl.Visible = true;
            }
            ctl = this.Controls.Find("status_Lbl" + counter, true).FirstOrDefault() as Control;
            if (ctl != null)
            {
                ctl.Text = "Initiated...";
            }

            counter++;
        }
        // Take input from text box
        count = Convert.ToInt32(pingSeconds_TxtBox.Text);
        // Start operation
        backgroundWorker1.RunWorkerAsync();
    }
}

自定义毫秒等待wait方法

public void wait(int milliseconds)
{
    var timer1 = new System.Windows.Forms.Timer();
    if (milliseconds == 0 || milliseconds < 0) return;

    timer1.Interval = milliseconds;
    timer1.Enabled = true;
    timer1.Start();

    timer1.Tick += (s, e) =>
    {
        timer1.Enabled = false;
        timer1.Stop();
    };

    while (timer1.Enabled)
    {
        Application.DoEvents();
    }
}

故障根因

  • BackgroundWorker的DoWork事件设计为在后台线程执行同步任务,给事件处理方法加async void修饰后,方法执行到第一个await断点时就会直接返回,BackgroundWorker会判定任务已执行完毕,立刻触发RunWorkerCompleted事件,这就是循环随机提前终止的核心原因。
  • 自定义wait方法使用System.Windows.Forms.Timer搭配Application.DoEvents()实现阻塞等待是WinForm开发中的典型反模式,会打乱UI线程消息泵的处理顺序,引入不可预知的重入问题,进一步加剧了异步状态错乱的故障。

最终解决方案

移除BackgroundWorker组件,改用async/await异步模式实现相关逻辑,该方案由Charlieface提供。


内容的提问来源于stack exchange,提问作者Thomton

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.27 14:09:15