【发布时间】:2013-04-24 13:47:16
【问题描述】:
假设我有一个带有两个按钮(button1 和button2)和一个资源对象(r)的表单。资源有自己的锁定和解锁代码来处理并发。资源可以被任何线程修改。
当点击button1 时,它的处理程序对r 本身进行一些修改,然后异步调用_IndependentResourceModifierAsync(),在一个衍生任务中对r 进行一些修改。 _IndependentResourceModifierAsync() 在执行此操作之前获取 r 的锁。也因为处理程序自己弄乱了r,它也获得了r的锁。
当button2被点击时,它只是直接调用_IndependentResourceModifierAsync()。它本身不会锁定。
如您所知,按钮的处理程序将始终在主线程上执行(生成的Task 除外)。
我要保证两件事:
- 如果在主线程锁定资源时单击
button1或button2,将引发异常。 (不能使用Monitor或Mutex,因为它们是线程驱动的) - 从
button1_Click()到_IndependentResourceModiferAsync()的锁嵌套不应导致死锁。 (不能使用Semaphore)。
基本上,我认为我正在寻找的是“基于堆栈的锁”,如果这样的事情存在或什至是可能的。因为当异步方法在等待之后继续时,它会恢复堆栈状态。我做了很多寻找其他有这个问题但没有找到的人。这可能意味着我把事情复杂化了,但我很好奇人们对此有什么看法。可能有一些非常明显的东西我错过了。非常感谢。
public class Resource
{
public bool TryLock();
public void Lock();
public void Unlock();
...
}
public class MainForm : Form
{
private Resource r;
private async void button1_Click(object sender, EventArgs e)
{
if (!r.TryLock())
throw InvalidOperationException("Resource already acquired");
try
{
//Mess with r here... then call another procedure that messes with r independently.
await _IndependentResourceModiferAsync();
}
finally
{
r.Unlock();
}
}
private async void button2_Click(object sender, EventArgs e)
{
await _IndependentResourceModifierAsync();
}
private async void _IndependentResourceModiferAsync()
{
//This procedure needs to check the lock too because he can be called independently
if (!r.TryLock())
throw InvalidOperationException("Resource already acquired");
try
{
await Task.Factory.StartNew(new Action(() => {
// Mess around with R for a long time.
}));
}
finally
{
r.Unlock();
}
}
}
【问题讨论】:
-
“第 1 件事”永远不会发生。
-
@HenkHolterman:为什么不呢?由于使用了异步,资源可以在不阻塞 UI 线程的情况下被“拥有”。
-
是的,我错过了等待。但是在锁内使用它似乎很奇怪。
-
我在锁中使用
await Task的原因是因为我需要GUI 立即知道它是否可以执行操作。如果不能,我可能会显示一条错误消息,并要求他们在最后一个操作完成后尝试。 -
你真的需要嵌套锁定吗?我相信这通常被认为是一种不好的做法。为什么不解除锁定
_IndependentResourceModiferAsync()并让被调用者处理呢?
标签: c# locking async-await