Блокировка с использованием атомарных операций

Да, я знаю, что на следующий вопрос можно было бы ответить с помощью «Вместо этого используйте ключевое слово блокировки» или чего-то подобного. Но так как это просто "для развлечения", меня это не волнует.

Я сделал простую блокировку, используя атомарные операции:

public class LowLock 
{
    volatile int locked = 0;

    public void Enter(Action action)
    {
        var s = new SpinWait();

        while (true)
        {
            var inLock = locked; // release-fence (read)

            // If CompareExchange equals 1, we won the race.
            if (Interlocked.CompareExchange(ref locked, 1, inLock) == 1)
            {
                action();
                locked = 0; // acquire fence (write)
                break; // exit the while loop
            }
            else s.SpinOnce(); // lost the race. Spin and try again.
        } 
    }
}

Я использую приведенную выше блокировку в простом цикле for, который добавляет строку к обычному List с помощью цель сделать метод add потокобезопасным, когда он заключен в метод Enter из LowLock .

Код выглядит так:

static void Main(string[] args)
{
    var numbers = new List<int>();

    var sw = Stopwatch.StartNew();
    var cd = new CountdownEvent(10000);

    for (int i = 0; i < 10000; i++)
    {
        ThreadPool.QueueUserWorkItem(o =>
        {
            low.Enter(() => numbers.Add(i));
            cd.Signal();
        });
    }

    cd.Wait();
    sw.Stop();

    Console.WriteLine("Time = {0} | results = {1}", sw.ElapsedMilliseconds, numbers.Count);

    Console.ReadKey();
}

Теперь сложная часть состоит в том, что когда основной поток попадает в Console.WriteLine , который печатает время и количество элементов в списке, количество элементов должно быть равным к счетчику, заданному для CountdownEvent (10000) - он работает большую часть времени, но иногда в списке всего 9983 элемента, иногда 9993. Что я упускаю из виду?

5
задан ebb 7 November 2011 в 15:52
поделиться