我在任务中运行此代码:
foreach (a in as) // yield return
{
component.Notify(...); // This component locks internally.
component.PropertyChanged += (o, args) =>
{
// Cancel out of task by adding another screen.
MainWindow.AddContent(new OtherComponent()); // WPF
}
}
现在,当在错误的时刻取消任务时,.Notify函数在已经取消后仍然会被调用,因为该任务仍在运行。我想要的是当调用.PropertyChanged事件时,不应再有.Notify调用之后。我当然可以在循环中使用一个相当简单的布尔值来解决这个问题,它会在下一次迭代中取消它,例如:
foreach (a in as) // yield return
{
if (requestCancel)
return;
component.Notify(...); // This component locks internally.
component.PropertyChanged += (o, args) =>
{
requestCancel = true;
}
}
此处的一个问题是foreach (a in as)
语句可能需要一段时间才能返回下一次迭代,因此在实际取消之前可能需要很长时间。我尝试使用锁定requestCancel操作,然后检查requestCancel是否为true,但这会导致死锁,因为component
在所有操作中都在内部使用锁。我不能改变它,因为它是第三方组件。我也试过一个信号量,一个读写器,但我总是陷入僵局。比如这个:
foreach (a in as) // yield return
{
_semaphore.WaitOne();
if (requestCancel)
return;
component.Notify(...); // This component locks internally.
component.PropertyChanged += (o, args) =>
{
_semaphore.WaitOne();
requestCancel = true;
}
_semaphore.Release();
}
基本上,.Notify被阻止,因为PropertyChanged仍在执行(由于内部都使用了锁)。这反过来导致PropertyChanged正在等待信号量或readerwriterlock的情况,而另一个块永远不会释放信号量,因为它正在等待PropertyChanged因锁定而完成。
我确实需要尽快取消此代码,并且在用户取消后无法再调用.Notify。在摆弄了一段时间之后,我已经没想完了。如果有任何不清楚的地方,请不要犹豫,要求提供进一步的信息。
答案 0 :(得分:0)
我认为,所有代码都在这样的一个线程上执行:
在这种情况下,信号量将始终阻止您的代码,因为在步骤2中您等待信号量发出信号,但这只发生在第3步之后。试试这个:
foreach (a in as) // yield return
{
component.PropertyChanged += (o, args) => requestCancel = true;
component.Notify(...);
// break out of the loop here to prevent getting next item from the enumerator
if (requestCancel)
break;
}
// do whatever you want to do after cancel
if (requestCancel)
MainWindow.AddContent(new OtherComponent());