Reputation: 215
I have the following problem. I have software which has access to a piece of hardware connected via USB.
In the UI there are some buttons (like search for device etc.)
And you can start a task which will lock the resource (USB device) and performs a time consuming operation on a background thread.
The problem is: If a button is pressed in the GUI which requires this resource, the whole UI will be blocked until the time consuming background thread has been completed (due to the lock).
I have a few ideas how to resolve this, but all seem to have a lot of drawbacks.
My ideas so far:
Check with Monitor.TryEnter if the resource can be accessed. ##The drawback is that this requires me to change all ICommand implementations (add the if statement)
Create another ICommand implementation which has a lock as additional parameter and only executes the method if this lock is free (i would like to have it as a predefined CanExecute statement). ## The problem is, that I am not sure that the change of CanExecute will be populated correctly (i could create a background task which periodically checks if the resource is free, but I think this could lead to racing conditions...)
I am looking for ideas how this can be resolved, if this is not a "constructive question" please feel free to mark it.
regards.
Upvotes: 1
Views: 1192
Reputation:
Inside your Execute()
, you can use Interlocked.CompareExchange()
to set a busy flag before spawning your worker.
Later in your CanExecute()
simply do a Interlocked.Read()
to test for "busy-ness".
When your worker completes, simply clear your busy flag by performing another Interlocked.Exchange()
.
The Interlocked
class is thread safe; pretty fast; and the above pattern won't block your UI.
Upvotes: 1
Reputation: 169160
You could use an asynchronous lock around your critical section. The .NET Framework provides the SemaphoreSlim
class that has an asynchronous WaitAsync
method:
System.Threading.SemaphoreSlim _lock = new System.Threading.SemaphoreSlim(1, 1);
//Asynchronously wait to enter the semaphore...
await _lock.WaitAsync();
try
{
//do your thing in the critical section
}
finally
{
_lock.Release();
}
There is also an AsyncLock
type which is an async almost equivalent version of the lock keyword available in Stephen Cleary's AsyncEx library that you may use: https://github.com/StephenCleary/AsyncEx/wiki/AsyncLock
Using an asynchronous lock you could wait for the lock to be released without blocking the UI thread.
Upvotes: 0