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

随声附和 提交于 2021-02-07 19:19:16

问题


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?


回答1:


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;
}



回答2:


Not sure if if helps anyone but this could be even simpler:

class RoundRobinNumber
{
    private int _maxNumbers = 10;
    private int _lastNumber = 0;

    public RoundRobinNumber(int maxNumbers)
    {
        _maxNumbers = maxNumbers;
    }

    public int GetNextNumber()
    {
        int nextNumber = Interlocked.Increment(ref _lastNumber);

        int result = nextNumber % _maxNumbers;  

        return result >= 0 ? result : -result;
    }
}



回答3:


Andrey's answer without conditional statements:

using System;
namespace Utils
{
    public class RoundRobinCounter
    {
        private int _max;
        private int _currentNumber = 0;

        public RoundRobinCounter(int max)
        {
            _max = max;
        }

        public int GetNext()
        {
            uint nextNumber = unchecked((uint)System.Threading.Interlocked.Increment(ref _currentNumber));
            int result = (int)(nextNumber % _max);
            return result;
        }
    }
}

And here is a .net fiddle running this code.



来源:https://stackoverflow.com/questions/10034289/how-should-i-increment-a-number-for-a-round-robin-threading-scenario-with-least

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!