0

ユーザーがフォームの特定の部分をクリックすると、同じフォームの別の領域の更新を開始する必要があります。これは、別のタスクを使用して行われます。更新がトリガーされ、進行中の更新がある場合は、それをキャンセルし、終了するのを待ってから、新しい更新を開始する必要があります。

私は 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
4

0 に答える 0