Trout
Trout

Reputation: 83

How to handle an Inifinite Loop in C#

I have a small program that's supposed to sample some value from a device connected via USB. I want to sample the device every 0.5 seconds - so I created a loop that repeats itself every 500miliseconds and works pretty well:

while(_bool)
{
    Sample_USB_Device();
    Present_Data_To_Screen();
}

My question is this:

How can I control the _bool variable? When I run the code the GUI freezes and I don't have any access to it. I tried to used Threads, but I can't send the data back from the thread to the GUI (or I don't know how).

Upvotes: 2

Views: 484

Answers (6)

holsee
holsee

Reputation: 1994

Using a Timer with C# 5.0 & TPL will allow you to invoke an async event handler which at the defined interval, which will poll the device and automagically marshall the result back onto the UI Thread.

public partial class Form1 : Form
{
    private readonly Timer _sampleTimer;

    public Form1()
    {
        InitializeComponent();

        _sampleTimer = new Timer
            {
                Interval = 500 // 0.5 Seconds
            };
        _sampleTimer.Tick += SampleUsb;
    }

    private async void SampleUsb(object sender, EventArgs e)
    {
        // Since we asynchronously wait, the UI thread is not blocked by "the work".
        var result = await SampleUsbDeviceAsync();

        // Since we resume on the UI context, we can directly access UI elements.
        resultTextField.Text = result;
    }

    private async Task<string> SampleUsbDeviceAsync()
    {
        await Task.Delay(1000); // Do actual work sampling usb async (not blocking ui)
        return DateTime.Now.Ticks.ToString(); // Sample Result
    }

    private void startButton_Click(object sender, EventArgs e)
    {
        _sampleTimer.Start();
    }

    private void stopButton_Click(object sender, EventArgs e)
    {
        _sampleTimer.Stop();
    }

Upvotes: 0

Heinzi
Heinzi

Reputation: 172468

Use a BackgroundWorker to execute your loop in the background. This will ensure that your UI stays responsive:

BackgroundWorker bw;

public void StartBackgroundLoop() {
    bw = new BackgroundWorker();
    bw.WorkerSupportsCancellation = true;
    bw.WorkerReportsProgress = true;

    bw.DoWork += (sender, e) => {
        // this will happen in a background thread
        while (!bw.CancellationPending) {
            data = Sample_USB_Device();
            bw.ReportProgress(0, data);
        }
    }

    // this event is triggered *in the UI thread* by bw.ReportProgress
    bw.ProgressChanged += (sender, e) => {
        Data data = (Data)e.UserState;  // this is the object passed to ReportProgress
        Present_Data_To_Screen(data);
    }

    bw.RunWorkerAsync(); // starts the background worker
}

public void StartBackgroundLoop() {
    bw.CancelAsync();     // sets bw.CancellationPending to true
}

Upvotes: 0

Mark Byers
Mark Byers

Reputation: 839114

You can use a Timer to run your code at a specified interval, instead of using a loop. The timer can be enabled or disabled.

Upvotes: 7

Yuki Kutsuya
Yuki Kutsuya

Reputation: 4098

Here, use a backgrounder.

backgroundWorker1.RunWorkerAsync(); // Start the backgroundworker.

private void backgroundWorker1_DoWork(object sender, System.ComponentModel.DoWorkEventArgs e)
{
    // Do you stuff here.
}

private void backgroundWorker1_ProgressChanged(object sender, System.ComponentModel.ProgressChangedEventArgs e)
{
    // Report the changes.
    // NOTE: backgroundWorker1.WorkerReportsProgress = true; has to be true.
}

private void backgroundWorker1_RunWorkerCompleted(object sender, System.ComponentModel.RunWorkerCompletedEventArgs e)
{
    // Do something when we are done.
}

EDIT: This only stops your freezing problem.

Upvotes: 0

jtm001
jtm001

Reputation: 371

  • You may be able to use a timer to fire an event for polling, but that can be limiting
  • You could run your poll in another thread but remember that you cannot update the gui except on the thread that created it ... use Invoke to do the updates in a gui safe manner
  • A threadsafe way to do your value on whether or not to continue your loop is to use the Interlocked.Read and Interlocked.Increment methods.

Upvotes: 0

Paul Grimshaw
Paul Grimshaw

Reputation: 21044

Use threading:

public class ThreadExample {
    private bool _running;
    public void start() {
       Thread t = new Thread(doStuff);
       _running = true;
       t.Start();
    }

    public void stop() {
       _running = false;
    }

    public void doStuff() {
        while(_running){
            Sample_USB_Device();
            Present_Data_To_Screen();
            Thread.Sleep(500);
        } 
    }
}

Upvotes: 0

Related Questions