我正在使用Keithley 2100数字万用表收集我正在写的一块校准软件的VAC读数。我已经制作了一个小型测试程序来收集Keithley IVI类库的一些数据,可以从他们的网站上下载。
我正在运行一个后台工作器,它正在从万用表收集输出,请参阅代码;
private void readButton_Click(object sender, EventArgs e) // gather readings
{
if (!backgroundWorker1.IsBusy)
{
address = Ke2100FunctionEnum.Ke2100FunctionACVolts;
range = Double.Parse(textBox2.Text);
resolution = Double.Parse(textBox3.Text);
backgroundWorker1.RunWorkerAsync();
}
else
{
MessageBox.Show("Task already enabled");
}
}
这是我的聚会阅读按钮,它检查以确保后台工作人员不忙,然后运行该工作人员。
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
while (true)
{
Invoke(new Action(() =>
{
ACResult = ke2100Device.Measure(address, range, resolution);
richTextBox1.Text += ACResult.ToString() + "\n";
}));
if(backgroundWorker1.CancellationPending)
{
backgroundWorker1.Dispose();
e.Cancel = true;
return;
}
Thread.Sleep(10);
}
}
ke2100Device.Measure
函数需要大约一秒钟才能处理一个阅读,但在这段时间内整个程序都没有响应,这是我在程序中无法做到的。我已经加载了任务管理器,看看我的核心是否有100%,因为它似乎是一个非常密集的功能,但我的用法很好。
我对如何解决这个问题感到有点困惑。我已经注释掉了ke2100Device.Measure
函数,只是让富文本框添加随机数,这可以正常工作而没有反应。
我唯一的想法似乎是做同样事情的另一种方式......喝咖啡休息!
- 编辑 -
更新了代码;
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
while (true)
{
ACResult = ke2100Device.Measure(address, range, resolution);
Invoke(new Action(() => { richTextBox1.Text += ACResult.ToString() + "\n"; }));
if (backgroundWorker1.CancellationPending)
{
e.Cancel = true;
return;
}
Thread.Sleep(10);
}
}
虽然如果我运行此调试代码来检查我的bgw;
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
while (true)
{
//ACResult = ke2100Device.Measure(address, range, resolution);
Invoke(new Action(() => { richTextBox1.Text += 0 + "\n"; })); //ACResult.ToString()
if (backgroundWorker1.CancellationPending)
{
e.Cancel = true;
return;
}
Thread.Sleep(10);
}
}
然后我没有任何挂起,或许Measure
函数存在实际问题?它可能正在做一些我没有完全意识到或看到的事情吗?
答案 0 :(得分:1)
对Measure
的调用应该在Invoke
操作之外。在Invoke
内调用它有效地在UI线程上运行它,使后台工作者变得毫无意义。
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
while (true)
{
ACResult = ke2100Device.Measure(address, range, resolution);
Invoke(new Action(() => { richTextBox1.Text += ACResult.ToString() + "\n"; }));
if(backgroundWorker1.CancellationPending)
{
//backgroundWorker1.Dispose(); // I don't think you want this here!
e.Cancel = true;
return;
}
Thread.Sleep(10);
}
}
答案 1 :(得分:1)
http://msdn.microsoft.com/en-us/library/cc221403(v=vs.95).aspx
由于您希望在每个度量上通知状态,因此您可能希望使用BackgroundWorker公开的ProgressChanged()
事件。您可以在调用ReportProgress()
时设置UserState属性。
这样做意味着您不必考虑是否致电Invoke()
,因为BackgroundWorker会为您隐藏此实施细节。
此外,如果每10毫秒更新一次GUI,即每秒100次更新,则用户可能无法注意到不同的更新。您可能希望将此值更改为可配置,然后使用它来获得所需的刷新率。
答案 2 :(得分:0)
我找到了这个问题。我直接了解设备如何与我的笔记本电脑通信,并发现它使用SCPI命令,所以从这一点开始我创建了两个非常简单的函数来创建连接,然后向万用表发送命令。 / p>
在此之后我意识到发送到万用表并返回的所有命令都是在命令行上完成的,这使我相信命令行和GUI线程实际上是同一个线程,这可以解释为什么整个尝试从我的设备读取数据时程序会挂起。
我是如何解决这个问题的?很容易,我把我的应用程序放在另一个线程上,然后加载它,看看代码!
Thread applicationThread = new Thread(() => Application.Run(new Form1()));
applicationThread.Start();
不再挂!我希望这可以帮助其他人。感谢帮助男生和女生!