ユーザーがフォームの特定の部分をクリックすると、同じフォームの別の領域の更新を開始する必要があります。これは、別のタスクを使用して行われます。更新がトリガーされ、進行中の更新がある場合は、それをキャンセルし、終了するのを待ってから、新しい更新を開始する必要があります。
私は TPL を初めて使用し、時間の制約により .NET 5 をまだ使用できません (VS2012 ライセンスは持っていますが、ソリューションをまだ移行していません)。コードは次のとおりです。
private mLoadGridLock = new Object();
private CancellationTokenSource mCancellationTokenSource;
private bool mLoadingFrames;
private Task mLoadingTask;
private List<string> mFramesList;
public FrameLoader(){
InitializeComponent();
mLoadingFrames = false;
mCancellationTokenSource = new CancellationTokenSource();
}
public void LoadGrid(){
lock (mLoadGridLock) {
if (mStudiesGrid.RowCount <= 0)
return;
Debug.WriteLine("--->LoadGrid Called");
if (mLoadingFrames) {
mCancellationTokenSource.Cancel();
Debug.WriteLine("--->Waiting for cancellation...");
mLoadingTask.Wait();
Debug.WriteLine("--->Wait for cancellation over!");
}
Debug.WriteLine("--->Launching new task");
mLoadingTask = Task.Factory.StartNew(() => LoadFrames(), mCancellationTokenSource.Token);
}
}
private void LoadFrames(){
mLoadingFrames = true;
Debug.WriteLine(" +++> Loader task started!");
int i = 0;
BeginInvoke(() => flp.Controls.Clear());
mFramesList = FrameRules.GenerateFrameList(this);
if (mFramesList <= 0)
return;
foreach (string framePath in mFramesList) {
if (mCancellationTokenSource.Token.IsCancellationRequested) {
mLoadingFrames = false;
Debug.WriteLine(" +++>Loader task cancelled");
return;
}
Debug.WriteLine(" +++>Loading frame " + i.ToString());
i = i + 1;
FrameOfReference fofr = new FrameOfReference();
fofr.BackgroundImage = My.Resources.Loading;
BeginInvoke(() => flp.Controls.Add(fofr));
Thread.Sleep(3000);
BeginInvoke(() => fofr.BackgroundImage == My.Resources.Done);
}
mLoadingFrames = false;
Debug.WriteLine(" +++>Loader task finished");
}
これは最初は問題なく実行されますが、2 回目ではデッドロックが発生します。これは一貫性のあるデバッグ出力です (常に同じです)。
--->LoadGrid Called
--->Launching new task
+++> Loader task started!
+++>Loading frame 0
+++>Loading frame 1
The thread 'ShowMessage-Execute' (0x168c) has exited with code 0 (0x0).
The thread 'Win32 Thread' (0x168c) has exited with code 0 (0x0).
+++>Loader task finished
--->LoadGrid Called
--->Launching new task
+++> Loader task started!
+++>Loading frame 0
--->LoadGrid Called
--->Waiting for cancellation...
2 回目に更新をトリガーしたときに LoadGrid が 2 回呼び出されることが問題の原因であることは明らかです。lock
そのため、ブロックを追加しました。しかし、これはまだハングします... これは TPL を使用する最初のショットなので、どんな入力も歓迎します。
UPDATE : に変更lock(this)
した後lock(mLoadGridLock)
、デッドロックは解消されましたが、2 回目または 3 回目の試みではフレームが読み込まれず、それ以降は何も読み込まれません。ログは次のとおりです。
--->LoadGrid Called
--->Launching new task
+++> Loader task started!
+++>Loading frame 0
The thread 'ShowMessage-Execute' (0xe50) has exited with code 0 (0x0).
The thread 'Win32 Thread' (0xe50) has exited with code 0 (0x0).
+++>Loading frame 1
+++>Loader task finished
--->LoadGrid Called
--->Launching new task
+++> Loader task started!
+++>Loading frame 0
--->LoadGrid Called
--->Waiting for cancellation...
+++>Loader task cancelled
--->Wait for cancellation over!
--->Launching new task