すべて、TaskSpin
TPL を使用してバックグラウンド スレッドで渡されたメソッドを実行するメソッドが呼び出されました。
public TaskSpin(Func asyncMethod, object[] methodParameters)
{
...
asyncTask = Task.Factory.StartNew<bool>(() =>
asyncMethod(uiScheduler, methodParameters));
asyncTask.ContinueWith(task =>
{
...
// Finish the processing update UI etc.
...
if (isStacked && task.Status == TaskStatus.RanToCompletion)
ProcessNextTask(dataGridViewSite);
}
...
}
このルーチンは、一度に 1 つのメソッドを起動するために十分に確立されていますが、最近、複数のメソッドをキューに入れ、それらを順番に実行する必要があります。これを行うには(この回答を参考に)、次のボタンクリックイベントハンドラーを作成しました
private void buttonProcAllUrg_Click(object sender, EventArgs e)
{
// Build the stacker.
Dictionary<Func<TaskScheduler, object[], bool>, object[]> taskPair =
new Dictionary<Func<TaskScheduler, object[], bool>, object[]>();
this.taskQueue =
new Queue<KeyValuePair<Func<TaskScheduler, object[], bool>, object[]>>();
// Populate the stacker.
foreach (DataGridViewRow row in this.DataGridViewDrg.Rows)
{
KeyValuePair<Func<TaskScheduler, object[], bool>, object[]> task =
new KeyValuePair<Func<TaskScheduler, object[], bool>, object[]>
(BuildDrgDataForSite, DrgDataRowInfo(row.Index));
this.taskQueue.Enqueue(task);
}
// Launch the queue.
ProcessNextTask(this.DataGridViewDrg);
}
そして、ProcessNextTask メソッドは次のように定義されます。
private void ProcessNextTask(DataGridView dataGridView)
{
try
{
// Queue empty.
bIsStacked = true;
if (this.taskQueue.Count <= 0)
{
bIsStacked = false;
return;
}
// Launch new task.
KeyValuePair<Func<TaskScheduler, object[], bool>, object[]> item = this.taskQueue.Dequeue();
Task<bool> asyncBuildDataTask = null;
TaskSpin(asyncBuildDataTask, uiScheduler, mainForm,
item.Key, item.Value, dataGridView,
"Process stack successfully executed", true, bIsStacked);
}
catch(InvalidOperationException)
{
// Nothing left in stack.
bIsStacked = false;
}
}
これは問題なく動作しますが、最初のタスクが実行された後ProcessNextTask
、継続から 2 回目 (またはそれ以上) が呼び出されると、GUI が応答しなくなります。2 回目の呼び出しで UI スレッドがブロックされないようにするにはどうすればよいですか?
ノート。ProcessNextTask
UI スレッド同期コンテキストを使用して別のスレッドでメソッドを起動しようとしました
Task task = Task.Factory.StartNew(() =>
{
ProcessNextTask(dataGridView);
}, CancellationToken.None,
TaskCreationOptions.LongRunning,
uiScheduler);
どこでTaskScheduler uiSchduler = TaskScheduler.FromCurrentSynchonisationContex();
。
編集:BlockingCollection
以下の@Reed Copseyの回答に基づいて、やりたいことを容易にするために作成しようとしましたが、これを行ったことはなく、ここでアドバイスを歓迎します
BlockingCollection<Action<object[]>> taskQueue =
new BlockingCollection<Action<object[]>>();
foreach (DataGridViewRow row in this.DataGridViewDrg.Rows)
{
Action<object[]> tmpAction = del =>
{AsyncBuildDrgDataForSite(DrgDataRowInfo(row.Index)); };
taskQueue.Add(tmpAction);
}
御時間ありがとうございます。