Ваше решение, кажется, не добавляет ничего, кроме сложности из-за гонки в TryLockedAction:
if (IsCorrupt(lockObject))
{
exception = new LockingException("Cannot execute locked action on a corrupt object.");
return false;
}
exception = null;
Monitor.Enter(lockObject);
LockObject может стать «поврежденным», пока мы все еще ждем на Monitor.Enter, так что нетзащита.
Я не уверен, какое поведение вы хотели бы достичь, но, вероятно, это поможет разделить блокировку и управление состоянием:
class StateManager
{
public bool IsCorrupted
{
get;
set;
}
public void Execute(Action body, Func fixState)
{
if (this.IsCorrupted)
{
// use some Exception-derived class here.
throw new Exception("Cannot execute action on a corrupted object.");
}
try
{
body();
}
catch (Exception)
{
this.IsCorrupted = true;
if (fixState())
{
this.IsCorrupted = false;
}
throw;
}
}
}
public class ExampleUsage
{
private readonly object ExampleLock = new object();
private readonly StateManager stateManager = new StateManager();
public void ExecuteLockedMethod()
{
lock (ExampleLock)
{
stateManager.Execute(ExecuteMethod, EnsureValidState);
}
}
private void ExecuteMethod()
{
//does something, maybe throws an exception
}
public bool EnsureValidState()
{
// code to make sure the state is valid
// if there is an exception returns false,
return true;
}
}
Кроме того, насколько я понимаюСуть статьи в том, что государственное управление сложнее при наличии параллелизма.Однако это все еще только проблема правильности состояния вашего объекта, которая ортогональна блокировке, и, вероятно, вам нужно использовать совершенно другой подход для обеспечения правильности.Например, вместо изменения какого-либо сложного состояния с помощью заблокированной области кода, создайте новое и, если оно выполнено успешно, просто переключитесь на новое состояние в одном простом назначении ссылки:
public class ExampleUsage
{
private ExampleUsageState state = new ExampleUsageState();
public void ExecuteLockedMethod()
{
var newState = this.state.ExecuteMethod();
this.state = newState;
}
}
public class ExampleUsageState
{
public ExampleUsageState ExecuteMethod()
{
//does something, maybe throws an exception
}
}
Лично я всегда склоненПодумайте, что ручная блокировка достаточно сложна для того, чтобы рассматривать каждый случай, когда она вам нужна индивидуально (поэтому нет особой необходимости в общих решениях по управлению состоянием), и достаточно низкоуровневый инструмент, чтобы использовать его действительно экономно.