クエリを非同期で実行するWindowsフォームツールを構築しようとしています。 このアプリケーションには、実行可能な30のクエリを含むdatagridviewがあります。ユーザーは、実行したいクエリー、例えば10個のクエリーをチェックし、ボタンを押す。 このアプリケーションには、クエリを非同期で実行するために使用できるスレッドの数を示すmaxthreads = 3という変数があります(説明のため)。クエリは実稼働環境で実行されるため、同時に実行されるスレッドが多すぎるためシステムに過負荷をかけたくありません。各クエリは平均30秒間実行されます。 (約5分、その他2秒) datagridviewには、各クエリーのステータスを示すアイコンを含むイメージ列があります(0-実行可能、1-選択、2-実行、3-正常に完了しました-1エラー) クエリが開始して終了するたびにUIと通信できる必要があります。クエリが終了すると、結果はTabControl(クエリごとに1つのタブ)に含まれるデータグリッドビューに表示されます複数のクエリをCで実行するマルチスレッドアプリケーションを作成する
アプローチ:私はいくつかのmaxthreadバックグラウンドワーカーを作成してクエリを実行させることを考えていました。バックグラウンド作業者が終了すると、UIと通信し、すべてのクエリが実行されるまで新しいクエリなどに割り当てられます。
作業をバックグラウンドワーカーにディスパッチするが、すべてのスレッドが終了するまで待つ方法はわからないassignmentWorkerを使ってみました。 bgwが終了すると、RunWorkerCompletedイベントの進行状況をassignmentWorkerに報告しますが、それは既に完了しています。私は実行する必要があるすべてのクエリに割り当て労働者を呼び出すUIスレッドで
:すべてが同じイベントを実行BGWprivate void assignmentWorker_DoWork(object sender, DoWorkEventArgs e)
{
foreach (Query q in (List<Query>)e.Argument)
{
while (!q.Processed)
{
for (int threadNum = 0; threadNum < maxThreads; threadNum++)
{
if (!threadArray[threadNum].IsBusy)
{
threadArray[threadNum].RunWorkerAsync(q);
q.Processed = true;
assignmentWorker.ReportProgress(1, q);
break;
}
}
//If all threads are being used, sleep awhile before checking again
if (!q.Processed)
{
Thread.Sleep(500);
}
}
}
}
:ここ
private void btnRunQueries_Click(object sender, EventArgs e)
{
if (AnyQueriesSelected())
{
tcResult.TabPages.Clear();
foreach (DataGridViewRow dgr in dgvQueries.Rows)
{
if (Convert.ToBoolean(dgr.Cells["chk"].Value))
{
Query q = new Query(dgr.Cells["ID"].Value.ToString(),
dgr.Cells["Name"].Value.ToString(),
dgr.Cells["FileName"].Value.ToString(),
dgr.Cells["ShortDescription"].Value.ToString(),
dgr.Cells["LongDescription"].Value.ToString(),
dgr.Cells["Level"].Value.ToString(),
dgr.Cells["Task"].Value.ToString(),
dgr.Cells["Importance"].Value.ToString(),
dgr.Cells["SkillSet"].Value.ToString(),
false,
new Dictionary<string, string>()
{ { "#ClntNb#", txtClntNum.Text }, { "#Staff#", "100300" } });
qryList.Add(q);
}
}
assignmentWorker.RunWorkerAsync(qryList);
}
else
{
MessageBox.Show("Please select at least one query.",
"Warning",
MessageBoxButtons.OK,
MessageBoxIcon.Information);
}
}
はAssignmentWorkerある
private void backgroundWorkerFiles_DoWork(object sender, DoWorkEventArgs e)
{
try
{
Query qry = (Query)e.Argument;
DataTable dtNew = DataAccess.RunQuery(qry).dtResult;
if (dsQryResults.Tables.Contains(dtNew.TableName))
{
dsQryResults.Tables.Remove(dtNew.TableName);
}
dsQryResults.Tables.Add(dtNew);
e.Result = qry;
}
catch (Exception ex)
{
}
}
クエリが返され、DataTableがデータセットに追加されたら:
private void backgroundWorkerFiles_RunWorkerCompleted(object sender,
RunWorkerCompletedEventArgs e)
{
try
{
if (e.Error != null)
{
assignmentWorker.ReportProgress(-1, e.Result);
}
else
{
assignmentWorker.ReportProgress(2, e.Result);
}
}
catch (Exception ex)
{
int o = 0;
}
}
私が持っている問題は、割り当て作業員がBGW仕上げの前に終了し、assignmentWorker.ReportProgressへの呼び出しは、(私のフランス語を言い訳)地獄に行くということです。 割り当てワーカーを終了する前に、起動したすべてのbgwが終了するのを待つ方法はありますか?
ありがとうございました!
私はバックグラウンドワーカーと割り当てワーカーに分割しません。このタスクは複雑すぎます。実行するクエリの 'foreach'がThreadPoolに作業を開始させるか、または動作スレッドの数が' maxthreads'以下になるのを待つバックグラウンドスレッドを持つことができます。処理するすべてのクエリが完了するまでループします。結果を表示するには、バックグラウンドタスクは、 'Dispatcher'を使ってメインUIスレッドで作業を開始し、UIを適切に更新して終了する必要があります。 – Mobigital