我知道这是我前一个问题的转贴......
c# wanting multiple ui threads but getting cross-reference errors instead
...但是我的后续问题没有得到解答,所以我再次发布新问题的帮助。我会在这里重复介绍。谢谢你的放纵。
我仍然非常擅长c#,线程和表单。我写了一个小数据采集程序。它有两个线程:一个传感器轮询/日志记录线程和一个可以绘制传感器数据图表的主UI线程。当用户单击“开始记录”按钮时,它会连续轮询传感器(通过虚拟COM端口),将响应写入文件,使用一些基本轮询统计信息更新主表单(每秒多少轮询)。如果用户单击了“监视器”按钮,它将打开一个图表表单,并且轮询线程开始启动一个方法,将传感器值添加到图表中。该程序运行良好,但我发现如果我打开多个图表(这样我可以实时查看多个传感器),图表更新将变得零星或停止,只有焦点更新的窗口才能顺利更新。 (通信端口只有56kbaud,因此不像投票被数据所淹没。)
所以我得到了制作图表线程的“明智”想法,认为这会提供多个UI循环(因此我可以与每个图表交互)并在多个图表表单上生成漂亮的平滑图表。以下是简化代码;例如此处,图表线程是使用轮询线程启动的,而不是在用户单击“监视器”按钮时启动。
问题是代理永远不会执行。主表单上的统计信息正在更新,显示图表格式,但没有响应,当我鼠标时,我得到“等待”光标。建议非常感谢。感谢。
namespace WindowsFormsApplication2
{
public partial class Main_Form : Form
{
delegate void UpdateUIStatsDelegate(string update);
UpdateUIStatsDelegate update_stats_delegate;
static BackgroundWorker polling_thread = new BackgroundWorker();
static BackgroundWorker charting_thread = new BackgroundWorker();
public static Chart_Form chart_form;
public Main_Form()
{
Thread.CurrentThread.Name = "main";
update_stats_delegate = new UpdateUIStatsDelegate(update_stats);
polling_thread.DoWork += polling_thread_DoWork;
charting_thread.DoWork += charting_thread_start;
}
private void start_polling_Click(object sender, EventArgs e)
{
// start polling thread
polling_thread.RunWorkerAsync();
// start charting plotting thread
charting_thread.RunWorkerAsync();
}
private void polling_thread_DoWork(object sender, DoWorkEventArgs e)
{
string sensor_values;
Thread.CurrentThread.Name = "polling";
while (true)
{
sensor_values = poll_the_sensors_and_collect_the_responses();
chart_form.BeginInvoke(chart_form.update_chart_delegate, new object[] { sensor_values });
pps = compute_polling_performance();
BeginInvoke(update_stats_delegate, new object[] { pps.ToString("00") });
}
}
private string poll_the_sensors_and_collect_the_responses()
{
send_command_to_sensor(sensor_id, command_to_return_current_readings);
return read_sensor_response(sensor_id);
}
private void update_stats(string stat)
{
pollings_per_second.Text = stat;
}
private void charting_thread_start(object sender, DoWorkEventArgs e)
{
Thread.CurrentThread.Name = "charting";
chart_form = new Chart_Form();
chart_form.Show();
while (charting_is_active) { }
}
}
public partial class Chart_Form : Form
{
public delegate void UpdateChartDelegate(string sensor_values);
public UpdateChartDelegate update_chart_delegate;
public Chart_Form()
{
update_chart_delegate = new UpdateChartDelegate(update_chart);
this.Text = "a realtime plot of sensor values";
}
private void update_chart(string sensor_values)
{
int x = extract_x_value(sensor_values);
int y = extract_y_value(sensor_values);
chart1.Series[X_AXIS].Points.AddY(x);
chart1.Series[Y_AXIS].Points.AddY(y);
}
}
}
答案 0 :(得分:1)
问题出在你的第二个UI线程中。你不能在UI线程中放置一个无限循环,期望它能够工作:
while (charting_is_active) { }
UI线程需要运行Windows消息队列。我的建议是,只在初始UI线程中创建两个表单。 但是如果你仍然想要采用两线程的方法,我认为你应该做一些事情:
private void charting_thread_start(object sender, DoWorkEventArgs e)
{
Thread.CurrentThread.Name = "charting";
Chart_Form chart_form = new Chart_Form();
Application.Run(chart_form);
}
答案 1 :(得分:0)
要跟进您的dotTrace数据:仔细查看这些数字。 138次调用OnPaint约8秒钟(绘制图表时为58ms)。另请注意,您已经将BeginInvoke称为2630次! update_logging_stats
被处理了2000多次 - 你的投票线程似乎运行得太快了。它比UI线程更快地为UI线程提供工作,或者显示器甚至可以渲染。
由于每次更新图表时都会调用update_logging_stats
一次,这意味着您的Windows消息队列积累了大量的绘制消息积压,无法跟上它们(这会导致您的UI线程扼流圈)。你只是给它太多的工作要做(方式超过必要的)。当它正忙于绘制图表时,又有二十条消息再次绘制它。最终它最终试图服务队列并锁定。
您可以尝试的是添加秒表并在图表上计量您的需求 - 仅每200毫秒左右发送一次更新:
private void polling_thread_DoWork(object sender, DoWorkEventArgs e)
{
string sensor_values;
Thread.CurrentThread.Name = "polling";
Stopwatch spw = new Stopwatch();
spw.Restart();
while (true)
{
sensor_values = poll_the_sensors_and_collect_the_responses();
if (spw.ElapsedMilliseconds > 200)
{
chart_form.BeginInvoke(chart_form.update_chart_delegate,
new object[] { sensor_values });
spw.Restart();
}
pps = compute_polling_performance();
BeginInvoke(update_stats_delegate, new object[] {pps.ToString("00")});
}
}
当然,如果您真的需要这样的分辨率,您仍然可以保留所有数据 - 当您不将它们添加到图表时,使用sensor_values
执行其他操作(将它们保存到数组,文件中)等)。你甚至可以考虑在200ms左右的时间内收集一些数据点然后立即发送一组点来绘制(而不是试图每秒重新绘制整数集) - 再次如果你真的在积累那个速度的数据。