如何在C#中处理Ininite循环

本文关键字:处理 Ininite 循环 | 更新日期: 2023-09-27 18:28:46

我有一个小程序,它应该从通过USB连接的设备中采样一些值。我想每0.5秒对设备进行一次采样,所以我创建了一个循环,每500毫秒重复一次,效果很好:

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

我的问题是:

如何控制_bool变量?当我运行代码时,GUI会冻结,我无法访问它。我尝试使用Threads,但我无法将数据从线程发送回GUI(或者我不知道如何发送)。

如何在C#中处理Ininite循环

您可以使用Timer以指定的间隔运行代码,而不是使用循环。可以启用或禁用计时器。

使用线程:

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);
        } 
    }
}
  • 您可以使用计时器触发事件进行轮询,但这可能会受到限制
  • 你可以在另一个线程中运行你的轮询,但请记住,除了在创建gui的线程上,你不能更新gui。。。使用Invoke以gui安全的方式进行更新
  • 关于是否继续循环,一种线程安全的方法是使用Interlocked.Read和Interlocked.Increment方法

在这里,使用背景。

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.
}

编辑:这只会阻止你的冷冻问题。

使用BackgroundWorker在后台执行循环。这将确保您的UI保持响应:

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
}

使用C#5.0&TPL将允许您调用异步事件处理程序,该处理程序将在定义的时间间隔轮询设备并自动将结果整理回UI线程。

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