I am trying to come with a solution for locking a global resources in a way that mandate locking for access and that is usable for sync or async operations.
I created a general class State:
public class State<T>
{
public class LockedState : IDisposable {
public LockedState(State<T> state) { this.state = state; Monitor.Enter(this.state.theLock); } // would be great if this could be private
public void Dispose() => Monitor.Exit(this.state.theLock);
public ref T Val { get { return ref state.t; } }
readonly State<T> state;
};
public State() { }
public State(T t) { this.t = t; }
public LockedState Locked { get { return new LockedState(this); } }
readonly object theLock = new object();
T t;
}
The idea here is that I can have a global 'store' ie in the Program class:
public class Program {
static public readonly State<ImmutableList<int>> TheList = new State<ImmutableList<int>>(ImmutableList<int>.Empty);
static public readonly State<SomeType> SomeType = new State<SomeType>(SomeType());
}
and then the only way to access the state is by acquiring the lock like this:
using (var lTheList = Program.TheList.Locked) {
lTheList.Val = lTheList.Val.Add(5));
}
which in my case works much better than a normal lock as it forces locking before get/set (you cannot forget to lock)
(side note is this a good strategy ?)
The issue is I cannot use the above in async code:
using (var someType = Program.SomeType.Lock()) {
var x = await someType.Val.SomeAsyncOp();
}
I get an exception: Object synchronization method was called from an unsynchronized block of code
I found this post How to protect resources that may be used in a multi-threaded or async environment? which has an AsyncLock class However I couldn't understand how to fit a class like AsyncLock into my StateLock class ..
Can State.Lock()
return a locked state that is usable for both sync and async callers ? that is really what I am looking for !
If not what is my best way forward ? using SemaphoreSlim
and having a State.Lock()
and a State.AsyncLock()
?
Thanks!