У нас есть метод, который поддерживает глобальный индекс последовательности всех событий в нашем приложении. Как и на веб-сайте, ожидается, что такой метод будет безопасным. Поточно-реализация была следующая:Interlocked.Increment и return incremented value
private static long lastUsedIndex = -1;
public static long GetNextIndex()
{
Interlocked.Increment(ref lastUsedIndex);
return lastUsedIndex;
}
Однако мы заметили, что в какой-то не большой нагрузке дублированных индексы появились в системе. Простой тест показал, что для 100000 итераций насчитывается около 1500 дубликатов.
internal class Program
{
private static void Main(string[] args)
{
TestInterlockedIncrement.Run();
}
}
internal class TestInterlockedIncrement
{
private static long lastUsedIndex = -1;
public static long GetNextIndex()
{
Interlocked.Increment(ref lastUsedIndex);
return lastUsedIndex;
}
public static void Run()
{
var indexes = Enumerable
.Range(0, 100000)
.AsParallel()
.WithDegreeOfParallelism(32)
.WithExecutionMode(ParallelExecutionMode.ForceParallelism)
.Select(_ => GetNextIndex())
.ToList();
Console.WriteLine($"Total values: {indexes.Count}");
Console.WriteLine($"Duplicate values: {indexes.GroupBy(i => i).Count(g => g.Count() > 1)}");
}
}
Это может быть исправлено с следующей реализацией:
public static long GetNextIndex()
{
return Interlocked.Increment(ref lastUsedIndex);
}
Однако, я не ясно понять, почему первая реализация не работает. Может ли кто-нибудь помочь мне описать, что происходит в этом случае?
Поскольку 'lastUsedIndex' мог быть обновлен другим вызовом' Interlocked.Increment' между получением результата и возвратом его вызывающему. –
Стандартная ошибка раскроя резьбы, другой поток также может увеличивать переменную прямо до 'return lastUsedIndex;' Маленькие коэффициенты, а не ноль. Код выполняет '[read modify write] read'. Гарантия атомарности, которую вы получаете от Interlocked, длится только для операций в скобках. Вам нужно будет использовать 'lock [read edit write read]', чтобы сделать его безопасным. –
RB, Hans Passant, понял. Может ли кто-нибудь из вас написать это как ответ, так что он будет полностью отвечать на вопрос? –