c#每100毫秒在单独的线程中轮询外部设备

时间:2014-04-10 14:09:17

标签: c# multithreading timer

我想构建一个程序,它将在单独的线程(UI线程除外)中每100毫秒与一些外部设备通信。我需要的是一些持续汇集的机制。

这是我第一次遇到多线程,我不知道如何正确地做到这一点......

据我所知,我可以使用System.Threading.Timer类来阻止用户GUI。

不幸的是,我的TimerCallback方法一开始就遇到了问题。我正在尝试使用System.Threading.Timer计时器。在调用TimerCallback程序突然退出后不久......我不明白为什么。有人可以帮我解释一下这种情况吗?

我的代码:

public partial class Form1 : Form
{
    System.Threading.Timer timer;
    TimerCallback tcb;

    private void btnButton_Click(object sender, EventArgs e)
    {
        tcb = new TimerCallback(PoolingStart);

        timer = new System.Threading.Timer(tcb, null, 0, Timeout.Infinite);    
    }

    public void PoolingStart(object state)
    {
       dgvGrid.Rows.Add(); //while debugging program exits here ... Why ? 
       //some API for external device which retrieve data from it
       timer.Change(0, 100);
    }
}

我不知道这种方法是否适合汇集外部设备。 也许有更好的方法来做到这一点。也许有人可以提示我一些解决方案? 无论如何 - 问题在于TimerCallback方法。在调用DataGridView控件后不久,整个程序退出。

我正在使用Visual Studio 2010,该项目是在Windows窗体中。

4 个答案:

答案 0 :(得分:1)

while debugging program exits here ... Why

因为您试图从另一个不允许的线程访问图形控件,所以在尝试从另一个线程访问控件的任何属性或方法之前尝试使用Control.InvokeRequired

答案 1 :(得分:1)

程序退出是因为您尝试从不是其所有者的线程访问控件( DataGrid )(换句话说,您正在尝试非法的跨线程异常)。 / p>

如果要从其他线程更新某些UI控件的内容,则需要使用Invoke(阻止调用)或BeginInvoke(非阻塞调用)。

在SO(或在网络上)你应该找到大量的例子:如果你需要一些特定的信息,请再次写在这里。

答案 2 :(得分:1)

由于计时器线程中的UI更新是非法的,因此您应该更改更新操作。

private void btnButton_Click(object sender, EventArgs e)
{
    timer = new System.Threading.Timer(new TimerCallback(PoolingStart));
    timer.Change(0, 100);
}
public void PoolingStart(object state)
{
    this.dgvGrid.Invoke(new MethodInvoker(() => { this.dgvGrid.Rows.Add(new DataGridViewRow()); }));            
}

答案 3 :(得分:1)

您可以使用Reactive Extensions RX-WinForms库。

public partial class Form1 : Form
{
    private const int PollIntervalMilliseconds = 100;
    private readonly Task _backgroundPoll;

    public Form1()
    {
        InititalizeComponents();
        _backgroundPoll = StartBackgroundPoll();
    }

    private Task StartBackgroundPoll()
    {
        return Observable
            .Interval(TimeSpan.FromMilliseconds(PollIntervalMilliseconds))
            .Select(_ => GetData())
            .ObserveOn(gdvGrid)
            .ForEachAsync(data => gdvGrid.Rows.Add(data));
    }
}