3c1f479b9d
Former-commit-id: 806294f5ded97629b74c85c09952f2a74fe182d9
307 lines
6.2 KiB
C#
307 lines
6.2 KiB
C#
//
|
|
// Snzi.cs
|
|
//
|
|
// Author:
|
|
// Jérémie "Garuma" Laval <jeremie.laval@gmail.com>
|
|
//
|
|
// Copyright (c) 2009 Jérémie "Garuma" Laval
|
|
//
|
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
// of this software and associated documentation files (the "Software"), to deal
|
|
// in the Software without restriction, including without limitation the rights
|
|
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
// copies of the Software, and to permit persons to whom the Software is
|
|
// furnished to do so, subject to the following conditions:
|
|
//
|
|
// The above copyright notice and this permission notice shall be included in
|
|
// all copies or substantial portions of the Software.
|
|
//
|
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
// THE SOFTWARE.
|
|
|
|
using System;
|
|
using System.Threading;
|
|
|
|
namespace Mono.Threading
|
|
{
|
|
interface ISnziNode
|
|
{
|
|
bool Query { get; }
|
|
void Arrive ();
|
|
void Depart ();
|
|
bool Reset ();
|
|
}
|
|
|
|
public class Snzi
|
|
{
|
|
readonly ISnziNode root;
|
|
readonly ISnziNode[] nodes;
|
|
|
|
readonly int count = Environment.ProcessorCount;
|
|
|
|
public Snzi ()
|
|
{
|
|
nodes = new ISnziNode[count];
|
|
root = new RootNode ();
|
|
for (int i = 0; i < count; i++)
|
|
nodes[i] = new LeafNode (root);
|
|
}
|
|
|
|
public void Increment ()
|
|
{
|
|
ISnziNode node = nodes[GetRandomIndex ()];
|
|
node.Arrive ();
|
|
}
|
|
|
|
public void Decrement ()
|
|
{
|
|
ISnziNode node = nodes[GetRandomIndex ()];
|
|
node.Depart ();
|
|
}
|
|
|
|
public void Reset ()
|
|
{
|
|
ISnziNode node = nodes[GetRandomIndex ()];
|
|
node.Reset ();
|
|
}
|
|
|
|
public bool IsSet {
|
|
get {
|
|
return !root.Query;
|
|
}
|
|
}
|
|
|
|
int GetRandomIndex ()
|
|
{
|
|
return (Thread.CurrentThread.ManagedThreadId) % count;
|
|
}
|
|
|
|
class UnsafeLeafNode : ISnziNode
|
|
{
|
|
ISnziNode parent;
|
|
int var;
|
|
|
|
public UnsafeLeafNode (ISnziNode parent)
|
|
{
|
|
this.parent = parent;
|
|
}
|
|
|
|
#region ISnziNode implementation
|
|
public void Arrive ()
|
|
{
|
|
int c = var++;
|
|
|
|
if (c == 0)
|
|
parent.Arrive ();
|
|
}
|
|
|
|
public void Depart ()
|
|
{
|
|
int c = var--;
|
|
if (c == 1)
|
|
parent.Depart ();
|
|
}
|
|
|
|
public bool Reset ()
|
|
{
|
|
throw new System.NotImplementedException();
|
|
}
|
|
|
|
public bool Query {
|
|
get {
|
|
return parent.Query;
|
|
}
|
|
}
|
|
#endregion
|
|
|
|
}
|
|
|
|
class LeafNode : ISnziNode
|
|
{
|
|
ISnziNode parent;
|
|
int var;
|
|
|
|
public LeafNode (ISnziNode parent)
|
|
{
|
|
this.parent = parent;
|
|
this.var = 0;
|
|
}
|
|
|
|
#region ISnziNode implementation
|
|
public void Arrive ()
|
|
{
|
|
bool succ = false;
|
|
int undoArr = 0;
|
|
while (!succ) {
|
|
int x = var;
|
|
short c, v;
|
|
Decode (x, out c, out v);
|
|
|
|
if (c >= 1)
|
|
if (Interlocked.CompareExchange (ref var, Encode ((short)(c + 1), v), x) == x)
|
|
break;
|
|
|
|
if (c == 0) {
|
|
int temp = Encode (-1, (short)(v + 1));
|
|
if (Interlocked.CompareExchange (ref var, temp, x) == x) {
|
|
succ = true;
|
|
c = -1;
|
|
v += 1;
|
|
x = temp;
|
|
}
|
|
}
|
|
|
|
if (c == - 1) {
|
|
parent.Arrive ();
|
|
if (Interlocked.CompareExchange (ref var, Encode (1, v), x) != x)
|
|
undoArr += 1;
|
|
}
|
|
}
|
|
for (int i = 0; i < undoArr; i++)
|
|
parent.Depart ();
|
|
}
|
|
|
|
public void Depart ()
|
|
{
|
|
while (true) {
|
|
int x = var;
|
|
short c, v;
|
|
Decode (x, out c, out v);
|
|
|
|
if (Interlocked.CompareExchange (ref var, Encode ((short)(c - 1), v), x) == x) {
|
|
if (c == 1)
|
|
parent.Depart ();
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
public bool Reset ()
|
|
{
|
|
throw new System.NotImplementedException();
|
|
}
|
|
|
|
public bool Query {
|
|
get {
|
|
return parent.Query;
|
|
}
|
|
}
|
|
#endregion
|
|
|
|
int Encode (short c, short v)
|
|
{
|
|
uint temp = 0;
|
|
temp |= (uint)c;
|
|
temp |= ((uint)v) << 16;
|
|
|
|
return (int)temp;
|
|
}
|
|
|
|
void Decode (int value, out short c, out short v)
|
|
{
|
|
uint temp = (uint)value;
|
|
c = (short)(temp & 0xFFFF);
|
|
v = (short)(temp >> 16);
|
|
}
|
|
}
|
|
|
|
class RootNode : ISnziNode
|
|
{
|
|
int var = 0;
|
|
int state = 0;
|
|
|
|
#region ISnziNode implementation
|
|
public void Arrive ()
|
|
{
|
|
int temp, x = 0;
|
|
short c, v;
|
|
bool a;
|
|
|
|
do {
|
|
x = var;
|
|
|
|
Decode (x, out c, out a, out v);
|
|
|
|
if (c == 0)
|
|
temp = Encode (1, true, (short)(v + 1));
|
|
else
|
|
temp = Encode ((short)(c + 1), a, v);
|
|
} while (Interlocked.CompareExchange (ref var, temp, x) != x);
|
|
|
|
Decode (temp, out c, out a, out v);
|
|
|
|
if (a) {
|
|
while (true) {
|
|
int i = state;
|
|
int newI = (i & 0x7FFFFFFF) + 1;
|
|
newI = (int)(((uint)newI) | 0x80000000);
|
|
if (Interlocked.CompareExchange (ref state, newI, i) == i) {
|
|
break;
|
|
}
|
|
}
|
|
Interlocked.CompareExchange (ref var, Encode (c, false, v), temp);
|
|
}
|
|
}
|
|
|
|
public void Depart ()
|
|
{
|
|
while (true) {
|
|
int x = var;
|
|
short c, v;
|
|
bool a;
|
|
Decode (x, out c, out a, out v);
|
|
|
|
if (Interlocked.CompareExchange (ref var, Encode ((short)(c - 1), false, v), x) == x) {
|
|
if (c >= 2)
|
|
return;
|
|
while (true) {
|
|
int i = state;
|
|
if (((short)(var >> 16)) != v)
|
|
return;
|
|
int newI = (i & 0x7FFFFFFF) + 1;
|
|
if (Interlocked.CompareExchange (ref state, newI, i) == i) {
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
public bool Reset ()
|
|
{
|
|
throw new System.NotImplementedException();
|
|
}
|
|
|
|
public bool Query {
|
|
get {
|
|
return (state & 0x80000000) > 0;
|
|
}
|
|
}
|
|
#endregion
|
|
|
|
int Encode (short c, bool a, short v)
|
|
{
|
|
uint temp = 0;
|
|
temp |= (uint)c;
|
|
temp |= (uint)(a ? 0x8000 : 0);
|
|
temp |= ((uint)v) << 16;
|
|
|
|
return (int)temp;
|
|
}
|
|
|
|
void Decode (int value, out short c, out bool a, out short v)
|
|
{
|
|
uint temp = (uint)value;
|
|
c = (short)(temp & 0x7FFF);
|
|
a = (temp & 0x8000) > 0;
|
|
v = (short)(temp >> 16);
|
|
}
|
|
}
|
|
}
|
|
}
|