Допустим, у меня есть форма с двумя кнопками (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();
}
}
}
await Task
в блокировке, заключается в том, что мне нужно, чтобы графический интерфейс сразу знал, может ли он выполнить операцию или нет. Если это невозможно, я могу отобразить сообщение об ошибке и попросить их попробовать, когда последняя операция будет завершена. - person Frank Weindel   schedule 24.04.2013_IndependentResourceModiferAsync()
и не позволить вызываемому обработать это? - person svick   schedule 24.04.2013Semaphore
, но ради этого поста скажем, что это нежелательно. - person Frank Weindel   schedule 24.04.2013