Interlocked.Increment and return incremented value

We have a method that supports the global sequence index of all events in our application. Like the website, it is expected that this method will be safe. The phased implementation was as follows:

private static long lastUsedIndex = -1;

public static long GetNextIndex()
{
    Interlocked.Increment(ref lastUsedIndex);
    return lastUsedIndex;
}

However, we noticed that with some not heavy load, duplicate indices appeared in the system. A simple test showed that for 100,000 iterations, there are about 1,500 duplicates.

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

This can be fixed with the following implementation:

public static long GetNextIndex()
{
    return Interlocked.Increment(ref lastUsedIndex);
}

However, I do not quite understand why the first implementation did not work. Can someone help me describe what happens in this case?

+4
2

, ,

Interlocked.Increment(ref someValue);

// Any number of operations

return someValue;

, concurrency ( parallelism, reentrance, preemptive code execution...) Increment return. , , someValue Increment, . - someValue () .

, , Interlocked.Increment - someValue++. Interlocked , , (), . , ( , , , CPU). . someValue ( , ).

" ", ? , . - .

( , someValue++), , , , someValue - . , (Interlocked.Increment is atomic), someValue.

, Interlocked.Increment - , . - , , . .

+2

, .

, lastUsedIndex == 5 2 .

Interlocked.Increment(ref lastUsedIndex);, lastUsedIndex 6. Interlocked.Increment(ref lastUsedIndex);, lastUsedIndex 7.

lastUsedIndex (, ). 7.

Interlocked.Increment(). (6 7). , , .

+2

Source: https://habr.com/ru/post/1669261/


All Articles