Dear Deer
Dear Deer

Reputation: 99

c# Polling external device in separate thread every 100 milliseconds

I would like to build a program, which will communicate with some external device every 100 milliseconds in separate thread (other than UI thread). What I need is some mechanism of continual pooling.

This is my first encounter with multithreading and I don't know how to do it properly...

As far as I read I could use System.Threading.Timer class to not block user GUI.

Unfortunately I have problems at the beginning with my TimerCallback method. I'm trying to use System.Threading.Timer timer. Shortly after invoking TimerCallback program suddenly exits ... I don't understand why. Could someone help me explain this situation?

My code:

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);
    }
}

I don't know if this approach is proper regarding pooling external devices though. Maybe there is a much better way to do this. maybe someone could prompt me some solution? Anyway - here the problem is with TimerCallback method. The whole program exits shortly after calling DataGridView control.

I'm using Visual Studio 2010 and the project is in Windows Forms.

Upvotes: 0

Views: 554

Answers (4)

Dustin Kingen
Dustin Kingen

Reputation: 21255

You can use Reactive Extensions RX-WinForms library.

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));
    }
}

Upvotes: 1

CuriousPen
CuriousPen

Reputation: 249

Because the UI update in timer thread is illegal, you should change your update operation.

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()); }));            
}

Upvotes: 1

Morix Dev
Morix Dev

Reputation: 2734

The program exits because you are trying to access a control (the DataGrid) from a thread which is not the its owner (in other words you are experimenting an illegal cross-thread exception).

If you want to update the content of some UI controls from a different thread then you need to use Invoke (blocking call) or BeginInvoke (non-blocking call).

Here on SO (or on the web in general) you should find tons of examples about that: if you need some specific info write here again.

Upvotes: 1

BRAHIM Kamel
BRAHIM Kamel

Reputation: 13764

while debugging program exits here ... Why

Because you are trying to access a graphic control from another thread which is not allowed try to use Control.InvokeRequired before you try access to any property or method of a control from another thread

Upvotes: 1

Related Questions