我正在尝试实现一个框架,用于在 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;
}
}
答案 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 中使用线程有一些非常好的含义。