I need to access a resource in a Windows 8.1 App shared by two processes: the app itself and a Background Task, so I need a named Semaphore
, SemaphoreSlim
does not apply there and as I do async work between acquisition and release I cannot use a Mutex
.
I have created a class in a PCL that creates the Semaphore and allows me to await the WaitOne
method this way:
public sealed class AsyncSemaphore:IDisposable
{
Semaphore _semaphore;
public AsyncSemaphore(int initialCount, int maximumCount, string name)
{
_semaphore = new Semaphore(initialCount, maximumCount, name);
}
public IAsyncOperation<bool> WaitOneAsync()
{
return AsyncInfo.Run<bool>(cancellationToken =>
Task.Run(()=>{
while (!_semaphore.WaitOne(100))
{
Logger.Log("Waiting...");
cancellationToken.ThrowIfCancellationRequested();
}
return true;
},cancellationToken));
}
public int Release()
{
return _semaphore.Release();
}
public void Dispose()
{
if (_semaphore != null)
{
_semaphore.Dispose();
_semaphore = null;
}
}
}
But WaitOneAsync
can be written also like this:
public IAsyncOperation<bool> WaitOneAsync()
{
return AsyncInfo.Run<bool>(async cancellationToken =>
{
while (!_semaphore.WaitOne(0))
{
Logger.Log("Waiting...");
await Task.Delay(100, cancellationToken);
}
return true;
});
}
Then I use it in my code like this:
_semaphore= new AsyncSemaphore(1,1,"uniquename");
//....
await _semaphore.WaitOneAsync();
try
{
//do more async work
}
finally
{
_semaphore.Release();
}
Is this correct? Which one is best and uses less resources?
The first option holds a thread throughout the entire wait, first by synchronously waiting and then by busy waiting (the while loop).
The second option is at least somewhat asynchronous as it uses Task.Delay
to wait and only then resorts to busy waiting.
The second (async) option uses less resources, but needs to wait out the entire timeout (100ms
) before checking again while the first (sync) can enter the semaphore immediately when it's released.
The async option uses less resources than the sync version but the actual synchronization is slower than in the sync version. So it comes down to what are your specific needs, scalability or speed.
You can optimize by lowering the timeout from 100ms
and so bring the async option closer and closer to the sync version.