120 lines
No EOL
4.1 KiB
C#
120 lines
No EOL
4.1 KiB
C#
// Copyright (c) 2006-2007 by Jeffrey Richter and Wintellect
|
|
|
|
// NOTE: I have not done extensive testing on my lock-free collections and
|
|
// I do not feel comfortable recommending their use at this time. This is
|
|
// why the classes are all 'internal'. As I personally have no need for these
|
|
// classes, I have suspended work on them. If people express more interest in
|
|
// them, then I may pursue working on them more in the future.
|
|
|
|
|
|
using System.Diagnostics.CodeAnalysis;
|
|
|
|
namespace JD.Collections.Lockless
|
|
{
|
|
internal class NodeManager<T>
|
|
{
|
|
[SuppressMessage("Microsoft.Design", "CA1000:DoNotDeclareStaticMembersOnGenericTypes",
|
|
Justification = "This is by design since this is a factory")]
|
|
public static NodeManager<T> Default = new NodeManager<T>();
|
|
public LocklessNode<T> Allocate() { return Allocate(default(T)); }
|
|
public virtual LocklessNode<T> Allocate(T item)
|
|
{
|
|
return new LocklessNode<T>(item);
|
|
}
|
|
public virtual void Free(LocklessNode<T> node)
|
|
{
|
|
node.Item = default(T); // Allow early GC
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
#region TestCode
|
|
#if false
|
|
namespace Ubi.Tools.Oasis.Shared.PowerThreading.Collections {
|
|
public static class Test {
|
|
public static void Test() {
|
|
PerfTest();
|
|
//StackTest();
|
|
//QueueTest();
|
|
}
|
|
|
|
static void PerfTest() {
|
|
const int iterations = 10000;
|
|
const int opsPerIteration = 1000;
|
|
Stack<int> s1 = new Stack<int>();
|
|
s1.Push(0); s1.Pop(); // JIT
|
|
using (new OperationTimer("s1, no locking")) {
|
|
for (int times = 0; times < iterations; times++) {
|
|
for (int x = 0; x < opsPerIteration; x++) { s1.Push(x); }
|
|
for (int x = 0; x < opsPerIteration; x++) { int z = s1.Pop(); }
|
|
}
|
|
}
|
|
|
|
using (new OperationTimer("s1, with locking")) {
|
|
for (int times = 0; times < iterations; times++) {
|
|
for (int x = 0; x < opsPerIteration; x++) { lock (s1) { s1.Push(x); } }
|
|
for (int x = 0; x < opsPerIteration; x++) { lock (s1) { int z = s1.Pop(); } }
|
|
}
|
|
}
|
|
|
|
LockFreeStack<int> lfs = new LockFreeStack<int>();
|
|
lfs.Push(0); lfs.Pop(); // JIT
|
|
using (new OperationTimer("lfs, no node pooling")) {
|
|
for (int times = 0; times < iterations; times++) {
|
|
for (int x = 0; x < opsPerIteration; x++) { lfs.Push(x); }
|
|
for (int x = 0; x < opsPerIteration; x++) { int z = lfs.Pop(); }
|
|
}
|
|
}
|
|
|
|
LockFreeStack<int> lfs2 = new LockFreeStack<int>(new NodePool<int>());
|
|
lfs2.Push(0); lfs2.Pop(); // JIT
|
|
using (new OperationTimer("lfs, with node pooling")) {
|
|
for (int times = 0; times < iterations; times++) {
|
|
for (int x = 0; x < opsPerIteration; x++) { lfs2.Push(x); }
|
|
for (int x = 0; x < opsPerIteration; x++) { int z = lfs2.Pop(); }
|
|
}
|
|
}
|
|
}
|
|
|
|
static void QueueTest() {
|
|
LockFreeQueue<Int32> q = new LockFreeQueue<int>(new NodePool<Int32>());
|
|
#if true
|
|
ThreadPool.QueueUserWorkItem(delegate(Object o) {
|
|
while (true) {
|
|
Int32 d;
|
|
if (q.TryDequeue(out d)) Console.WriteLine(d);
|
|
};
|
|
});
|
|
#endif
|
|
Int32 z;
|
|
while (q.TryDequeue(out z)) Console.WriteLine(z);
|
|
for (int x = 0; x < 100; x += 2) {
|
|
q.Enqueue(x);
|
|
Thread.Sleep(0);
|
|
}
|
|
while (q.TryDequeue(out z)) Console.WriteLine(z);
|
|
Console.ReadLine();
|
|
}
|
|
|
|
static void StackTest() {
|
|
LockFreeStack<Int32> s = new LockFreeStack<int>(new NodePool<Int32>());
|
|
ThreadPool.QueueUserWorkItem(delegate(Object o) {
|
|
while (true) {
|
|
Int32 d;
|
|
if (s.TryPop(out d)) Console.WriteLine(d);
|
|
};
|
|
});
|
|
Int32 z;
|
|
while (s.TryPop(out z)) Console.WriteLine(z);
|
|
for (int x = 0; x < 100; x += 2) {
|
|
s.Push(x);
|
|
Thread.Sleep(0);
|
|
}
|
|
//while (s.TryPop(out z)) Console.WriteLine(z);
|
|
Console.ReadLine();
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
#endregion |