对于争用最少的轮循机制线程方案,我应该如何递增一个数字
本文关键字:我应该 方案 何递增 一个 线程 数字 争用 于争用 机制 | 更新日期: 2023-09-27 18:30:23
如果许多线程使用以下代码同时调用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
重置回 1,并可靠地为每个调用 GetNextNumber()
的线程返回一个递增的数字,而不必使用锁?
Andrey 没有条件语句的答案:
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 小提琴。
诀窍是在循环中执行操作,直到成功。我在这里的回答中为这种方法提供了一个通用模板。
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;
}
不确定是否对任何人有帮助,但这可能更简单:
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;
}
}
通常使用循环从集合中选择项目。根据亚历克斯的回答,我做了一个RoundRobinCollection
变体。
public class RoundRobinCollection<T>
{
private readonly ReadOnlyCollection<T> _collection;
private int _currentNumber = -1;
public RoundRobinCollection(IEnumerable<T> enumerable)
{
_collection = new List<T>(enumerable).AsReadOnly();
if (!_collection.Any())
{
throw new InvalidOperationException("Cannot use empty collection for RoundRobinCollection.");
}
}
public T GetNext()
{
var index = GetNextIndex();
return _collection[index];
}
private int GetNextIndex()
{
// This increments the currentNumber in a Thread-safe way, and deals with exceeding int.MaxValue properly
var nextNumber = unchecked((uint)Interlocked.Increment(ref _currentNumber));
return (int)(nextNumber % _collection.Count);
}
}
使用示例:
public class SomeClient
{
private readonly RoundRobinCollection<ServerConfig> _serverConfigs;
public SomeClient(List<ServerConfig> serverConfigs)
{
_serverConfigs = new RoundRobinCollection<ServerConfig>(serverConfigs);
}
public void DoSomething(){
var serverConfig = _serverConfigs.GetNext();
// Do something with current serverConfig
}
}