使用带有计时器的Backgroundworker

时间:2014-09-01 21:37:55

标签: c# backgroundworker

我已经在很多地方看过这个但仍未找到解决方案。我想要实现的是能够在定时的基础上使用BackgroundWorker。这是一个例子:

    public Main()
    {

        isDbAvail = new BackgroundWorker();
        isDbAvail.DoWork += isOnline;
        isDbAvail.RunWorkerCompleted += rewriteOnlineStatus; 


    }

    private void rewriteOnlineStatus(object sender, RunWorkerCompletedEventArgs e)
    {
        Subs.Connection connection = new Subs.Connection();
        changeStatus(connection.isDbAvail());
    }

    private void isOnline(object sender, DoWorkEventArgs e)
    {
        while (true)
        {
            Console.WriteLine("Checking database connection");
            System.Threading.Thread.Sleep(8000);
        }
    }

    public void changeStatus(bool status)
    {
        if (status)
        {
            serverStatusVal.Text = "Connected";
            serverStatusVal.ForeColor = System.Drawing.Color.DarkGreen;
        }
        else
        {
            serverStatusVal.Text = "Not connected";
            serverStatusVal.ForeColor = System.Drawing.Color.Red;
        }
    }

这里发生的是isOnline方法每8秒检查一次与数据库的连接(只是一个例子)并相应地更改文本。我注意到的是,isOnline方法中的while循环导致rewriteOnlineStatus方法永远不会触发,因为它无限期地运行。还有另一种解决方法吗?

2 个答案:

答案 0 :(得分:2)

我建议您使用BackgroundWorker.ReportProgress,并检查后台线程中的连接。

这样的事情:

public Main()
{
    isDbAvail = new BackgroundWorker();
    isDbAvail.WorkerReportsProgress = true;
    isDbAvail.DoWork += isOnline;
    isDbAvail.ProgressChanged += rewriteOnlineStatus; 
    isDbAvail.RunWorkerAsync();
}

private void rewriteOnlineStatus(object sender, ProgressChangedEventArgs e)
{        
    changeStatus((bool)e.UserState);
}

private void isOnline(object sender, DoWorkEventArgs e)
{
    while (true)
    {
        Console.WriteLine("Checking database connection");
        Subs.Connection connection = new Subs.Connection();
        isDbAvail.ReportProgress(0, connection.isDbAvail);
        System.Threading.Thread.Sleep(8000);
    }
}

现在,BackgroundWorker正在开展工作,并通过ProgressChanged向UI线程报告。

答案 1 :(得分:0)

这应该是评论,而不是答案,但是我没有足够的声誉积分可以发表评论。 (我对此限制感到困惑。)

@blorgbeard的回答是正确的,但是此问题的真正重要部分是如何在后台线程中模拟计时器,而不会意外退出线程。

他实际上根本不在工作线程中使用计时器。毕竟,将使用计时器在间隔后唤醒线程并对其进行控制。由于线程已经具有控制权,所以窍门就是在相等的时间间隔内放弃该控制权。他使用睡眠,然后使用while (true)循环返回以再次执行线程的工作。

这是由他的这段代码执行的:

while (true)
{
    // Perform the periodic background work
    // This can update data structures used by the UI when it paints
    CallMyRoutineToRefreshDataForUI();

    // Optionally report to UI. 
    isDbAvail.ReportProgress(0, connection.isDbAvail);

    // Use Sleep to give up control, rather than using a Timer to regain control
    System.Threading.Thread.Sleep(8000);
}

此方法具有更大的适应性。就我而言,我可以更改在对话框中查找的信息。然后,即使睡眠计时器尚未过期,我也需要强制后台线程运行。

如果后台工作线程正在休眠并且无法检查取消标志,则取消后台工作线程将不会有任何效果。取而代之的是,我在Sleep周围放置了while循环,一次只睡眠了100毫秒。我将睡眠间隔放入一个外部变量中,而不是对其进行硬编码。当我需要强制运行线程时,我只是将间隔降低为1 ms,然后让它重新循环。 (我本来可以很好地使用BackgroundWorker的Cancel功能,但是无论如何我在调整Sleep间隔时还有其他编码方面的考虑。)