如何在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(或者我不知道如何发送)。
您可以使用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();
}