I have a system that takes Samples. I have multiple client threads in the application that are interested in these Samples, but the actual process of taking a Sample can only occur in one context. It's fast enough that it's okay for it to block the calling process until Sampling is done, but slow enough that I don't want multiple threads piling up requests. I came up with this design (stripped down to minimal details):
public class Sample
{
private static Sample _lastSample;
private static int _isSampling;
public static Sample TakeSample(AutomationManager automation)
{
//Only start sampling if not already sampling in some other context
if (Interlocked.CompareExchange(ref _isSampling, 0, 1) == 0)
{
try
{
Sample sample = new Sample();
sample.PerformSampling(automation);
_lastSample = sample;
}
finally
{
//We're done sampling
_isSampling = 0;
}
}
return _lastSample;
}
private void PerformSampling(AutomationManager automation)
{
//Lots of stuff going on that shouldn't be run in more than one context at the same time
}
}
Is this safe for use in the scenario I described?
Yes, it looks safe because int
is an atomic type here. But I would still advice replacing
private static int _isSampling;
with
private static object _samplingLock = new object();
and use :
lock(_samplingLock)
{
Sample sample = new Sample();
sample.PerformSampling(automation);
_lastSample = sample;
}
Simply because it is the recommended pattern and also makes sure all access to _lastSample is treated correctly.
NB: I would expect comparable speed, lock uses the managed Monitor class that uses Interlocked internally.
Edit:
I missed the back-off aspect, here is another version :
if (System.Threading.Monitor.TryEnter(_samplingLock))
{
try
{
.... // sample stuff
}
finally
{
System.Threading.Monitor.Exit(_samplingLock);
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With