Lock-free array-based stack
От: vf  
Дата: 27.02.10 16:07
Оценка: 1 (1)
Коллеги, возникло непреодолимое желание поделиться своим велосипедом, получить комментарии, может кому пригодится Готового на .нет не нашел, вот сделал свое, с пятой попытки.

Основная задача, была сделать tread-safe пул буферов для сервера, первоначально реализовал это дело через lock, скорость работы lock подхода вынудила копать дальше, в сторону Interlocked, потом узал что правильно такой подход называется lock-free, а так же, что часто возникающая проблема в таких алгоритмах называется ABA (я с ней столкнулся в 3-4 попытке).
В процессе работы над пулом и появился ниже приведенный Stack. В последствии, находил ссылки на pdf-ы с алгоритмами LIFO, FIFO, но не разбирался, вероятно там тоже самое. Читал про .нет 4.0, но там, по описанию, алгоритмы основаны на SpinLock, так что возможно мое будет чуть быстрее (хотя и со своими ограничениями)

class SafeStackItem<T>
{
    public T Value;
    public volatile Int32 Next;
}

class SafeStack<T>
    where T : class
{
    private volatile Int32 head;
    private volatile Int32 count;
    private SafeStackItem<T>[] array;

    public SafeStack(SafeStackItem<T>[] array, int pushFrom, int pushCount)
    {
        this.head = -1;
        this.array = array;

        count = pushCount;

        head = pushFrom;
        for (int i = 0; i < pushCount - 1; i++)
            array[i + pushFrom].Next = pushFrom + i + 1;
        array[pushFrom + pushCount - 1].Next = -1;
    }

#pragma warning disable 0420

    public Int32 Pop()
    {
        while (count > 1)
        {
            Int32 head1 = head;
            Int32 next1 = Interlocked.Exchange(ref array[head1].Next, -1);

            if (next1 >= 0)
            {
                if (Interlocked.CompareExchange(ref head, next1, head1) == head1)
                {
                    Interlocked.Decrement(ref count);
                    return head1;
                }
                else
                    Interlocked.Exchange(ref array[head1].Next, next1);
            }
        }

        return -1;
    }

    public void Push(Int32 index)
    {
        Int32 head1, head2;
        do
        {
            head1 = head;
            array[index].Next = head1;
            head2 = Interlocked.CompareExchange(ref head, index, head1);
            
        } while (head1 != head2);

        Interlocked.Increment(ref count);
    }

#pragma warning restore 0420
}
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.