什么是并发任务队列的最佳替代方案,而不是使用.net 4.0

时间:2014-02-20 12:43:25

标签: c# multithreading concurrency queue

我正在尝试实现一个框架,用于在 Unity 应用程序中使用多个内核。

到目前为止,我所拥有的是由{em> Julian M Bucknal 实施的non-blocking queue。它似乎对我的目的非常有效。我创建了一个任务类和一个结果类,并使用两个队列来分发和收集在辅助线程上处理的工作。

剩下的问题是,由于此代码将在我的应用程序的性能关键部分中大量使用,我真的希望尽量减少垃圾收集器的使用。

是否有可以帮助我改进的已知库/模板/技术?

using System.Threading;

public class LockFreeQueue<T> {
    internal struct SingleLinkNode<U> where U : T {
        // Note; the Next member cannot be a property since
        // it participates in many CAS operations
        public SingleLinkNode<U> Next;
        public U Item;
    }
    static private bool CAS<V>(ref V location, V comparand, V newValue) where V : class {
        return
            (object) comparand ==
            (object) Interlocked.CompareExchange<V>(ref location, newValue, comparand);
    }

    SingleLinkNode<T> head;
    SingleLinkNode<T> tail;

    public LockFreeQueue() {
        head = new SingleLinkNode<T>();
        tail = head;
    }

    public void Enqueue(T item) {
        SingleLinkNode<T> oldTail = null;
        SingleLinkNode<T> oldTailNext;

        SingleLinkNode<T> newNode = new SingleLinkNode<T>();
        newNode.Item = item;

        bool newNodeWasAdded = false;
        while (!newNodeWasAdded) {
            oldTail = tail;
            oldTailNext = oldTail.Next;

            if (tail == oldTail) {
                if (oldTailNext == null)
                    newNodeWasAdded = CAS<SingleLinkNode<T>>(ref tail.Next, null, newNode);
                else
                    CAS<SingleLinkNode<T>>(ref tail, oldTail, oldTailNext);
            }
        }
        CAS<SingleLinkNode<T>>(ref tail, oldTail, newNode);
    }

    public bool Dequeue(out T item) {
        item = default(T);
        SingleLinkNode<T> oldHead = null;

        bool haveAdvancedHead = false;
        while (!haveAdvancedHead) {

            oldHead = head;
            SingleLinkNode<T> oldTail = tail;
            SingleLinkNode<T> oldHeadNext = oldHead.Next;

            if (oldHead == head) {
                if (oldHead == oldTail) {
                    if (oldHeadNext == null) {
                        return false;
                    }
                    CAS<SingleLinkNode<T>>(ref tail, oldTail, oldHeadNext);
                } else {
                    item = oldHeadNext.Item;
                    haveAdvancedHead = CAS<SingleLinkNode<T>>(ref head, oldHead, oldHeadNext);
                }
            }
        }
        return true;
    }

    public T Dequeue() {
        T result;
        Dequeue(out result);
        return result;
    }
}

1 个答案:

答案 0 :(得分:2)

我设法通过重用SingleLinkNode<T>的实例来最小化垃圾收集。

这是我自定义的非阻塞堆栈:

using System.Threading;

public class LockFreeLinkPool<T> {

    private SingleLinkNode<T> head;

    public LockFreeLinkPool() {
        head = new SingleLinkNode<T>();
    }

    public void Push(SingleLinkNode<T> newNode) {
        newNode.Item = default(T);
        do {
            newNode.Next = head.Next;
        } while (!SyncMethods.CAS<SingleLinkNode<T>>(ref head.Next, newNode.Next, newNode));
        return;
    }

    public bool Pop(out SingleLinkNode<T> node) {
        do {
            node = head.Next;
            if (node == null) {
                return false;
            }
        } while (!SyncMethods.CAS<SingleLinkNode<T>>(ref head.Next, node, node.Next));
        return true;
    }
}

我在存储之前和之后仔细清理所有实例SingleLinkNode。这对我们在 Unity 中使用线程有一些非常好的含义。