等待任务完成时死锁

时间:2013-02-15 13:52:54

标签: c# task-parallel-library

当用户点击表单的某个部分时,我需要开始更新同一表单的另一个区域。这是使用单独的任务完成的。事实是,如果触发更新并且正在进行更新,我需要取消它,等待它完成,然后启动一个新的。

我是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");
}

第一次运行正常,但在第二次运行时我遇到了僵局。这是调试输出,它是一致的(它总是相同的):

--->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...

很明显,问题是由于第二次触发更新时LoadGrid被调用两次引起的;这就是我添加lock块的原因。但这仍然悬而未决......这是我第一次使用TPL,所以任何输入都是受欢迎的。

更新:将lock(this)更改为lock(mLoadGridLock)后,死锁消失,但在第二次或第三次尝试时,它不会加载任何帧,从那时起它没有加载。这是一个日志:

--->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

0 个答案:

没有答案