Search code examples
c#multithreadinginterlocked

How should I increment a number for a round robin threading scenario with least contention?


If many threads are calling GetNextNumber simultaneously with the following code, GetNextNumber will return 1 more times than any other numbers.

private class RoundRobbinNumber
{
    private int _maxNumbers = 10;
    private int _lastNumber;

    private RoundRobbinNumber(int maxNumbers)
    {
        _maxNumbers = maxNumbers;
    }

    public int GetNextNumber()
    {
        int nextNumber = Interlocked.Increment(ref _lastNumber);
        if (_lastNumber > _maxNumbers)
        {
            Interlocked.CompareExchange(ref _lastNumber, 1, _maxNumbers);
            nextNumber = 1;
        }
        return nextNumber;
    }
}

Is there a way to reset the _lastNumber back to one, and reliably return an incremented number for each thread calling GetNextNumber(), without having to use a lock?


Solution

  • The trick is to do the operation in a loop until it is successful. I provide a general template for this approach in my answer here.

    public int GetNextNumber()
    {
      int initial, computed;
      do
      {
        initial = _lastNumber;
        computed = initial + 1;
        computed = computed > _maxNumbers ? computed = 1 : computed;
      } 
      while (Interlocked.CompareExchange(ref _lastNumber, computed, initial) != initial);
      return computed;
    }