Reputation: 171
The system I am working on is composed of a Windows service hosting various WCF services. Multiple clients can talk to a same service, but only one client can talk to a service at time.
I am therefore using a "lock ()" to prevent multiple clients to conflict. If Client1 makes a first request to a service and then Client2 makes another requested while the former is still executing, the "lock" puts that second request on hold until the first one is done.
So far so good. Now the problem is that I have to deal with events (I don't think a simple callback would do the trick here).
In other words, while the 1st request is running, something may happen that Client2 needs to know about.
When that happens, Client2 will receive that event and should eventually stop using that service all together.
The problem here is that our 2nd request is already in the locker's queue.
So how would I prevent that second request from running. Can it get cancelled?
Maybe it is just a matter of adding a dirty flag but I am hoping there are better ways to do that.
Here is what it may look like on the service side with the dirty flag "canRun":
lock (_locker)
{
if (canRun)
return SomeMethod();
else
return null;
}
Upvotes: 1
Views: 146
Reputation: 1064114
If you can switch to async
/await
and something like a SemaphoreSlim
, then: CancellationToken
is what you're looking for; a CancellationTokenSource
can be marked as cancelled at any time, and code can respond accordingly - and most framework/library code already correctly handles cancellation, for example: during async semaphore acquisition.
If you need to stick in a synchronous world, then your best bet is probably to change to a looped Monitor
mode that can re-check every timeout, for example:
bool lockTaken = false;
try
{
do
{
if (!canRun) throw new OperationCanceledException();
Monitor.TryEnter(_locker, someTimeout, ref lockTaken);
}
while (!lockTaken);
// now we have the conch
SomeMethod();
}
finally
{
if (lockTaken) Monitor.Exit(_locker);
}
Note that if canRun
is a field you would want to ensure that it is either volatile
or otherwise accessed suitably to avoid being cached in a register or similar.
Upvotes: 1