私はまだC#、スレッド、フォームの初心者です。小さなデータ取得プログラムを書いています。2 つのスレッドがあります。メインの UI スレッドと、センサーのポーリング/ログ記録/グラフ作成スレッドです。ユーザーが「ログ開始」ボタンをクリックすると、(仮想 COM ポートを介して) センサーを継続的にポーリングし、応答をファイルに書き込み、いくつかの基本的なポーリング統計 (1 秒あたりのポーリング数) でメイン フォームを更新します。ユーザーが「モニター」ボタンをクリックすると、チャート フォームが開き、ポーリング スレッドがセンサー値をチャートに追加するメソッドを呼び出します。
非常にうまく機能するこのプログラムのバージョンがありますが、(複数のセンサーをリアルタイムで表示できるように) 複数のチャートを開いていると、チャートの更新が散発的または停止し、フォーカスのあるウィンドウのみがスムーズに更新されることがわかりました。(通信ポートは 56kbaud しかないので、ポーリングがデータであふれているわけではありません。)
そこで、複数の UI ループが提供され、複数のチャート フォームでスムーズなチャートが生成されると考えて、チャート スレッドを作成するという「明るい」アイデアを得ました。以下は簡略化されたコードです。たとえば、ここでは、チャート作成スレッドは、ユーザーが「モニター」ボタンをクリックしたときではなく、ポーリング スレッドで開始されます。コンパイルはできますが、実行すると、 update_chart メソッドが呼び出された時点で相互参照エラーが発生します。
スレッドとコントロールの所有権についていくつかのことを根本的に誤解しているようです。チャートは「charting」スレッドで作成されましたが、「polling」スレッドが update_chart メソッドを呼び出すと、コードは update_chart メソッドが「main_ui」スレッドによって実行されていることを示しています。スムーズなチャート作成と統計の更新を可能にする提案やアドバイスをお待ちしています。ありがとう。
namespace WindowsFormsApplication1
{
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 = new Chart_Form();
public Main_Form()
{
Thread.CurrentThread.Name = "main_ui";
update_stats_delegate = new UpdateUIStatsDelegate(update_stats);
polling_thread.DoWork += polling_thread_DoWork;
charting_thread.DoWork += charting_thread_start;
}
private void start_logging_Click(object sender, EventArgs e)
{
start_polling_thread();
start_charting_thread();
}
private void start_polling_thread()
{
polling_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();
log_to_file(sensor_values);
// BeginInvoke(chart_form.update_chart_delegate, new object[] { sensor_values });
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 void update_stats(string stat)
{
string tn = Thread.CurrentThread.Name;
// this says "main_ui", but i don't get a cross-reference error
pollings_per_second.Text = stat;
}
private void start_charting_thread()
{
charting_thread.RunWorkerAsync();
}
private void charting_thread_start(object sender, DoWorkEventArgs e)
{
Thread.CurrentThread.Name = "charting";
Chart_Form 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()
{
string tn = Thread.CurrentThread.Name;
update_chart_delegate = new UpdateChartDelegate(update_chart);
this.Text = "a realtime plot of sensor values";
}
private void update_chart(string sensor_values)
{
string tn = Thread.CurrentThread.Name;
// this says "main_ui" and i get a cross reference error; set below.
int x = extract_x_value(sensor_values);
int y = extract_y_value(sensor_values);
chart1.Series[X_AXIS].Points.AddY(x); // <<--- i get a cross-reference runtime error here...
chart1.Series[Y_AXIS].Points.AddY(y);
}
}
}