如何使用带有计时器滴答的BackgroundWorker?

时间:2012-08-04 18:26:30

标签: c# multithreading timer

决定不使用任何计时器。 我做的更简单。

添加了背景工作者。 在加载了所有构造函数后,在已显示的事件中添加了一个Shown事件。 在显示的事件中,我启动了backgroundworker异步。

在后台工作人员DoWork中:

private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
        {
            while(true)
            {
                cpuView();
                gpuView();
                Thread.Sleep(1000);
            }
        }

6 个答案:

答案 0 :(得分:6)

在这种情况下,最好使用两个System.Threading.Timer并在这两个线程中执行cpu密集型操作。请注意,必须使用BeginInvoke访问控件。您可以将这些访问封装到属性设置器中,甚至可以更好地将它们拉出到视图模型类中。

public class MyForm : Form
{
    private System.Threading.Timer gpuUpdateTimer;
    private System.Threading.Timer cpuUpdateTimer;

    protected override void OnLoad(EventArgs e)
    {
        base.OnLoad(e);

        if (!DesignMode)
        {
            gpuUpdateTimer = new System.Threading.Timer(UpdateGpuView, null, 0, 1000);
            cpuUpdateTimer = new System.Threading.Timer(UpdateCpuView, null, 0, 100);
        }
    }

    private string GpuText
    {
        set
        {
            if (InvokeRequired)
            {
                BeginInvoke(new Action(() => gpuLabel.Text = value), null);
            }
        }
    }

    private string TemperatureLabel
    {
        set
        {
            if (InvokeRequired)
            {
                BeginInvoke(new Action(() => temperatureLabel.Text = value), null);
            }
        }
    }

    private void UpdateCpuView(object state)
    {
        // do your stuff here
        // 
        // do not access control directly, use BeginInvoke!
        TemperatureLabel = sensor.Value.ToString() + "c" // whatever
    }

    private void UpdateGpuView(object state)
    {
        // do your stuff here
        // 
        // do not access control directly, use BeginInvoke!
        GpuText = sensor.Value.ToString() + "c";  // whatever
    }

    protected override void Dispose(bool disposing)
    {
        if (disposing)
        {
            if (cpuTimer != null)
            {
                cpuTimer.Dispose();
            }
            if (gpuTimer != null)
            {
                gpuTimer.Dispose();
            }
        }

        base.Dispose(disposing);
    }

答案 1 :(得分:2)

您不能将此代码抛入后台工作程序并期望它能够正常工作。需要在主线程上调用更新UI元素(标签,文本框,...)的任何内容。您需要打破逻辑以获取更新UI的数据和逻辑。

我想说你最好的办法就是这样做:

在计时器Tick()方法中:

// Disable the timer.
// Start the background worker

在后台worker DoWork()方法中:

// Call your functions, taking out any code that 
// updates UI elements and storing this information 
// somewhere you can access it once the thread is done.

在后台工作者Completed()方法中:

// Update the UI elements based on your results from the worker thread
// Re-enable the timer.

答案 2 :(得分:2)

首先要确保能够解决多重呼吸困难问题(尤其是UI问题)。

然后你可以使用像

这样的想法
public class Program
{
    public static void Main(string[] args)
    {
        Timer myTimer = new Timer(TimerTick, // the callback function
            new object(), // some parameter to pass
            0, // the time to wait before the timer starts it's first tick
            1000); // the tick intervall
    }

    private static void TimerTick(object state)
    {
        // less then .NET 4.0
        Thread newThread = new Thread(CallTheBackgroundFunctions);
        newThread.Start();

        // .NET 4.0 or higher
        Task.Factory.StartNew(CallTheBackgroundFunctions);
    }

    private static void CallTheBackgroundFunctions()
    {
        cpuView();
        gpuView();
    }
}

请注意(就像John Koerner告诉您的那样)cpuView()gpuView()将无法正常工作。

答案 3 :(得分:1)

是的,你可以:

在您的计时器刻度事件中:

private void timer_Tick(object sender, EventArgs e)
{

  timer.Enabled = false;

  backgroundworker.RunWorkerAsync();

  timer.Enabled = true;
}

在你的Backgroundworker dowork事件中:

private void backgroundworker_DoWork(object sender, System.ComponentModel.DoWorkEventArgs e)
{
   try
   {
       //Write what you want to do
   }
   catch (Exception ex)
   {
       MessageBox.Show("Error:\n\n" + ex.Message, "System", MessageBoxButtons.OK, MessageBoxIcon.Error);
   }
}

答案 4 :(得分:0)

我认为BackgroundWorker对于案件来说太复杂了;使用Timer很难实现有保证的停止。

我建议您使用工作人员Thread,并在您需要的时间间隔内等待取消ManualResetEvent的循环:

  • 如果设置了取消事件,则工作人员退出循环。
  • 如果超时(您需要的时间间隔超过),则执行系统监控。

以下是代码的草稿版本。请注意我没有测试过它,但它可以告诉你这个想法。

public class HardwareMonitor
{
    private readonly object _locker = new object();
    private readonly TimeSpan _monitoringInterval;
    private readonly Thread _thread;
    private readonly ManualResetEvent _stoppingEvent = new ManualResetEvent(false);
    private readonly ManualResetEvent _stoppedEvent = new ManualResetEvent(false);

    public HardwareMonitor(TimeSpan monitoringInterval)
    {
        _monitoringInterval = monitoringInterval;
        _thread = new Thread(ThreadFunc)
            {
                IsBackground = true
            };
    }

    public void Start()
    {
        lock (_locker)
        {
            if (!_stoppedEvent.WaitOne(0))
                throw new InvalidOperationException("Already running");

            _stoppingEvent.Reset();
            _stoppedEvent.Reset();
            _thread.Start();
        }
    }

    public void Stop()
    {
        lock (_locker)
        {
            _stoppingEvent.Set();
        }
        _stoppedEvent.WaitOne();
    }

    private void ThreadFunc()
    {
        try
        {
            while (true)
            {
                // Wait for time interval or cancellation event.
                if (_stoppingEvent.WaitOne(_monitoringInterval))
                    break;

                // Monitoring...
                // NOTE: update UI elements using Invoke()/BeginInvoke() if required.
            }
        }
        finally
        {
            _stoppedEvent.Set();
        }
    }
}

答案 5 :(得分:0)

在我的情况下,我在 WinForm BackgroundWorker System.Timers.Timer ProgressBar >申请。我遇到的是第二个问题,我将重复BackgroundWorker的工作我尝试在BackgroundWorker的ProgressChanged中更新ProgressBar时得到跨线程异常。然后我找到了一个< SO @ Rudedog2 https://stackoverflow.com/a/4072298/1218551上的strong>解决方案,它说当初始化Timers.Timer对象以用于Windows窗体时,必须将timer实例的SynchronizingObject属性设置为窗体。 / p>

systemTimersTimerInstance.SynchronizingObject = this; // this = form instance.

http://msdn.microsoft.com/en-us/magazine/cc164015.aspx