Reputation: 9252
The below code is a very simplified example of what I am trying to accomplish.
private object _highestLevelLock = new object();
private int _highestValue;
private void SetHighestValue()
{
var random = new Random();
var next = random.Next(0, 100);
if (next > _highestValue)
{
lock (_highestLevelLock)
{
if(next > _highestValue)
_highestValue = next;
}
}
}
Namely, I have a variable that holds the highest integer that I have come across so far. SetHighestValue() can be accessed by multiple threads.
If the random integer generated is larger than the currently largest integer, I will update the _highestValue.
My question is, how can I avoid checking twice if next > highestValue? If I remove it from inside the lock, then there is the risk that _highestValue will get set to something even higher, before this thread sets the value, and in this scenario, _highestValue will be inaccurate.
I know that I can get rid of the if statement outside the lock, but I do not want to lock unnecessarily.
Is there a better way to accomplish this? Potentially some combination of locking and/or using the Interlocked namespace?
On a somewhat related note, should _highestValue be volatile? Even if so, I assume that will not help with my question at hand.
Thanks!
Upvotes: 1
Views: 336
Reputation: 144136
I think you can use the Interlocked
class instead of locking:
Each thread with a higher value tries to perform the update, but re-checks if it fails:
var next = random.Next(0, 100);
int current = _highestValue;
bool updated = false;
while(next > current && !updated)
{
updated = Interlocked.Exchange(ref _highestValue, next, current);
current = _highestValue;
}
Upvotes: 1
Reputation: 28302
What you are describing is a case of test and test and set and is a very efficient way of handling things. To answer your question, short of encapsulating your condition in a function there is no way to get rid of the code duplication.
Upvotes: 2