Reputation: 25287
I'm writing a asynchronous library using begin/end, and I need to lock objects.
Currently, I'm doing this using semaphores, but calling semaphore.WaitOne()
suspends the thread where it is called. I'd rather use something like BeginWait so it would return immediately and call the callback function when the semaphore is free.
Is there such an object in c#?
Upvotes: 2
Views: 466
Reputation: 25287
Actually, this is what I ended up with - maybe someone will find it useful:
class AsyncSemaphore
{
public AsyncSemaphore(int counter, int maxCounter)
{
this.maxCounter = maxCounter;
this.counter = counter;
}
private int maxCounter, counter;
class CallbackObject:IAsyncResult
{
private AsyncCallback callback;
#region IAsyncResult Members
public object AsyncState { get; set; }
public System.Threading.WaitHandle AsyncWaitHandle
{
get
{
throw new NotImplementedException();
}
}
public bool CompletedSynchronously { get; set; }
public bool IsCompleted { get; set; }
public AsyncCallback Callback
{
get { return callback; }
set { callback = value; }
}
#endregion
}
private ConcurrentQueue<CallbackObject> queue = new ConcurrentQueue<CallbackObject>();
public IAsyncResult BeginWait(AsyncCallback callback, object state)
{
if (callback==null)
{
throw new ArgumentNullException("callback","callback cannot be null");
}
var o=new CallbackObject();
o.AsyncState = state;
o.Callback = callback;
bool execute = false;
if (Interlocked.Decrement(ref this.counter)>=0)
{
o.CompletedSynchronously= execute = true;
}
else
{
queue.Enqueue(o);
}
if (execute)
{
callback(o);
o.IsCompleted = true;
}
return o;
}
public void EndWait(IAsyncResult r)
{}
public void Release()
{
CallbackObject execute = null;
if (Interlocked.Increment(ref this.counter)<1)
{
if (!queue.TryDequeue(out execute))
{
throw new NotImplementedException("ConcurrentQueue.TryDequeue failed");
}
}
else
{
if (counter > maxCounter)
{
throw new SemaphoreFullException("Release was called too many times");
}
}
if (execute!=null)
{
execute.Callback(execute);
execute.IsCompleted = true;
}
}
}
Upvotes: 0
Reputation: 203802
You can use the WaitAsync
method of SemaphoreSlim
(.NET 4.5+) to get a Task
that will be completed when the semaphore is next available. You can add a continuation to that task to have a callback that will be called when the semaphore is active.
Upvotes: 2