4

多くのスレッドがGetNextNumber次のコードと同時に呼び出している場合、GetNextNumberは他のどの番号よりも1回多く返されます。

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

ロックを使用せずに、_lastNumber元に戻して、スレッド呼び出しごとに増分された数を確実に返す方法はありますか?GetNextNumber()

4

3 に答える 3

4

条件文なしのアンドレイの答え:

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

そして、これがこのコードを実行する.net フィドルです。

于 2016-12-08T17:28:07.167 に答える
4

トリックは、成功するまでループで操作を行うことです。ここでの回答で、このアプローチの一般的なテンプレートを提供します。

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;
}
于 2012-04-05T19:01:52.730 に答える