Commits

Anonymous committed 148c4e6 Draft

initial commit

Comments (0)

Files changed (76)

+obj/
+bin/
+\.log
+\.Cache
+\.pfx
+\.suo

Cineraria.Concurrency/Barrier.cs

+// -----------------------------------------------------------------------
+// <copyright file="Barrier.cs">
+//     Copyright (c) Rhys 2012-03-15. All rights reserved.
+// </copyright>
+// -----------------------------------------------------------------------
+
+// TODO: max 80 cols
+namespace Cineraria.Concurrency
+{
+    using System;
+
+    /// <summary>
+    /// A multiple-use thread barrier mechanism.
+    /// </summary>
+    public class Barrier
+    {
+        /// <summary>
+        /// Object used for lock() blocks.
+        /// </summary>
+        /// <remarks>See http://stackoverflow.com/questions/251391/why-is-lockthis-bad </remarks>
+        private readonly object _syncRoot = new object();
+
+        /// <summary>
+        /// Turnstile to prevent threads racing through <see cref="Arrive()"/>.
+        /// </summary>
+        private Semaphore _turnstile = new Semaphore(1);
+
+        /// <summary>
+        /// A semaphore representing permission to continue through the barrier.
+        /// </summary>
+        private Semaphore _goPermission = new Semaphore(0);
+
+        /// <summary>
+        /// The number of threads that have arrived at the barrier.
+        /// </summary>
+        private int _count = 0;
+
+        /// <summary>
+        /// The number of threads that must arrive for the barrier to open.
+        /// </summary>
+        private int _threshold;
+
+        /// <summary>
+        /// Whether this barrier is broken.
+        /// </summary>
+        private bool _isBroken = false;
+
+        /// <summary>
+        /// Whether this barrier is open, ie. threshold was met and threads can leave.
+        /// </summary>
+        private bool _isOpen = false;
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="Barrier"/> class.
+        /// </summary>
+        /// <param name="threshold">The number of threads that must arrive for the barrier to open.</param>
+        /// <exception cref="ArgumentOutOfRangeException"><paramref name="threshold"/> must be greater than zero.</exception>
+        public Barrier(int threshold)
+        {
+            if (threshold < 1)
+            {
+                throw new ArgumentOutOfRangeException("threshold");
+            }
+
+            this._threshold = threshold;
+        }
+
+        /// <summary>
+        /// Gets the number of threads that must arrive for the barrier to open.
+        /// </summary>
+        public int Threshold
+        {
+            get { return this._threshold; }
+        }
+
+        /// <summary>
+        /// Waits until <see cref="Threshold"/> threads have arrived at this
+        /// barrier.
+        /// </summary>
+        /// <returns>
+        /// An int indicating the order in which this thread left this barrier.
+        /// </returns>
+        /// <exception cref="BrokenBarrierException">
+        /// Another thread has broken this barrier.
+        /// </exception>
+        public int Arrive()
+        {
+            return this.Arrive(-1);
+        }
+
+        /// <summary>
+        /// Waits until <see cref="Threshold"/> threads have arrived at this
+        /// barrier or <paramref name="milliseconds"/> pass.
+        /// </summary>
+        /// <param name="milliseconds">
+        /// The maximum number of milliseconds to wait before breaking this
+        /// barrier.
+        /// </param>
+        /// <returns>
+        /// An int indicating the order in which this thread left this barrier.
+        /// </returns>
+        /// <exception cref="ArgumentOutOfRangeException">
+        /// <paramref name="milliseconds"/> must be positive or -1.
+        /// </exception>
+        /// <exception cref="BrokenBarrierException">
+        /// This thread or another thread has broken this barrier.
+        /// </exception>
+        public int Arrive(int milliseconds)
+        {
+            if (milliseconds < -1 || milliseconds == 0)
+            {
+                throw new ArgumentOutOfRangeException("milliseconds");
+            }
+
+            this._turnstile.Acquire();
+
+            lock (this._syncRoot)
+            {
+                if (this._isBroken)
+                {
+                    this._turnstile.Release();
+                    throw new BrokenBarrierException();
+                }
+
+                this._count++;
+                if (this._count == this._threshold)
+                {
+                    this._isOpen = true;
+                    this._goPermission.Release(this._threshold);
+                }
+                else
+                {
+                    this._turnstile.Release();
+                }
+            }
+
+            bool acquiredGoPermission = this._goPermission.Attempt(
+                milliseconds);
+
+            lock (this._syncRoot)
+            {
+                this._count--;
+                if (!acquiredGoPermission && this._isOpen)
+                {
+                    this._goPermission.Acquire();
+                    acquiredGoPermission = true;
+                }
+
+                if (acquiredGoPermission)
+                {
+                    if (this._count == 0)
+                    {
+                        this._isOpen = false;
+                        this._turnstile.Release();
+                    }
+
+                    if (this._isBroken)
+                    {
+                        throw new BrokenBarrierException();
+                    }
+
+                    return this._count;
+                }
+                else
+                {
+                    this._isBroken = true;
+                    this._goPermission.Release(this._count);
+                    this._turnstile.Release();
+                    throw new BrokenBarrierException();
+                }
+            }
+        }
+    }
+}

Cineraria.Concurrency/BorkBuffer.cs

+// -----------------------------------------------------------------------
+// <copyright file="BorkBuffer.cs">
+//     Copyright (c) Rhys 2012-03-08. All rights reserved.
+// </copyright>
+// -----------------------------------------------------------------------
+
+namespace Cineraria.Concurrency
+{
+    using System.Collections.Generic;
+    using System.Threading;
+
+    /// <summary>
+    /// A thread-safe generic buffer that throws exceptions when empty.
+    /// </summary>
+    /// <typeparam name="T">The type stored in the buffer.</typeparam>
+    public class BorkBuffer<T> : IBuffer<T>
+    {
+        /// <summary>
+        /// The underlying queue.
+        /// </summary>
+        private readonly Queue<T> _queue = new Queue<T>();
+
+        /// <summary>
+        /// Object used for lock() blocks.
+        /// </summary>
+        /// <remarks>See http://stackoverflow.com/questions/251391/why-is-lockthis-bad </remarks>
+        private readonly object _syncRoot = new object();
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="BorkBuffer&lt;T&gt;"/> class.
+        /// </summary>
+        public BorkBuffer()
+        {
+        }
+
+        /// <summary>
+        /// Puts the specified item into the buffer.
+        /// </summary>
+        /// <param name="item">The item.</param>
+        public void Put(T item)
+        {
+            lock (this._syncRoot)
+            {
+                this._queue.Enqueue(item);
+            }
+        }
+
+        /// <summary>
+        /// Takes an item from the buffer.
+        /// </summary>
+        /// <returns>The item.</returns>
+        /// <exception cref="System.InvalidOperationException">
+        /// The buffer is empty.
+        /// </exception>
+        public T Take()
+        {
+            lock (this._syncRoot)
+            {
+                return this._queue.Dequeue();
+            }
+        }
+    }
+}

Cineraria.Concurrency/BoundedChannel.cs

+// -----------------------------------------------------------------------
+// <copyright file="BoundedChannel.cs">
+//     Copyright (c) Rhys 2012-03-08. All rights reserved.
+// </copyright>
+// -----------------------------------------------------------------------
+namespace Cineraria.Concurrency
+{
+    using ThreadInterruptedException = System.Threading.ThreadInterruptedException;
+
+    /// <summary>
+    /// A thread-safe channel with a capacity limit.
+    /// </summary>
+    /// <typeparam name="T">The type stored in the channel.</typeparam>
+    public class BoundedChannel<T> : Channel<T>
+    {
+        /// <summary>
+        /// A semaphore representing permission to put an item in the channel.
+        /// Enforces the capacity limit.
+        /// </summary>
+        private readonly Semaphore _putPermission;
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="BoundedChannel&lt;T&gt;"/> class.
+        /// </summary>
+        /// <param name="limit">The capacity limit.</param>
+        public BoundedChannel(int limit)
+            : base()
+        {
+            this._putPermission = new Semaphore(limit);
+        }
+
+        /// <summary>
+        /// Puts the specified item into the channel. If the channel is full, waits a maximum of
+        /// <paramref name="milliseconds"/> before giving up.
+        /// </summary>
+        /// <param name="item">The item.</param>
+        /// <param name="milliseconds">The maximum number of milliseconds to wait before giving up.</param>
+        /// <returns>true if the specified item was put in the buffer, false otherwise.</returns>
+        public override bool Offer(T item, int milliseconds)
+        {
+            if (this._putPermission.Attempt(milliseconds))
+            {
+                try
+                {
+                    return base.Offer(item, milliseconds);
+                }
+                catch (ThreadInterruptedException)
+                {
+                    this._putPermission.ForceRelease();
+                    throw;
+                }
+            }
+
+            return false;
+        }
+
+        /// <summary>
+        /// Attempts to take an item from the buffer, waiting a maximum of
+        /// <paramref name="milliseconds"/> before giving up.
+        /// </summary>
+        /// <param name="item">The item taken.</param>
+        /// <param name="milliseconds">The maximum number of milliseconds to wait before giving up.</param>
+        /// <returns>true if a item was taken, false otherwise.</returns>
+        public override bool Poll(out T item, int milliseconds)
+        {
+            if (base.Poll(out item, milliseconds))
+            {
+                this._putPermission.ForceRelease();
+                return true;
+            }
+            else
+            {
+                return false;
+            }
+        }
+    }
+}

Cineraria.Concurrency/BrokenBarrierException.cs

+// -----------------------------------------------------------------------
+// <copyright file="BrokenBarrierException.cs">
+//     Copyright (c) Rhys. All rights reserved.
+// </copyright>
+// -----------------------------------------------------------------------
+
+namespace Cineraria.Concurrency
+{
+    using System;
+    using System.Runtime.Serialization;
+
+    /// <summary>
+    /// An exception indicating the barrier a thread arrived at is broken.
+    /// </summary>
+    [Serializable]
+    public class BrokenBarrierException : Exception
+    {
+        /// <summary>
+        /// Initializes a new instance of the
+        /// <see cref="BrokenBarrierException"/> class.
+        /// </summary>
+        public BrokenBarrierException()
+            : base()
+        {
+        }
+
+        /// <summary>
+        /// Initializes a new instance of the
+        /// <see cref="BrokenBarrierException"/> class with a specified error
+        /// message.
+        /// </summary>
+        /// <param name="message">The message that describes the error.</param>
+        public BrokenBarrierException(string message)
+            : base(message)
+        {
+        }
+
+        /// <summary>
+        /// Initializes a new instance of the
+        /// <see cref="BrokenBarrierException"/> class with a specified error
+        /// message and a reference to the inner exception that is the cause of
+        /// this exception.
+        /// </summary>
+        /// <param name="message">
+        /// The error message that explains the reason for the exception.
+        /// </param>
+        /// <param name="innerException">
+        /// The exception that is the cause of the current exception, or a null
+        /// reference (Nothing in Visual Basic) if no inner exception is
+        /// specified.
+        /// </param>
+        public BrokenBarrierException(string message, Exception innerException)
+            : base(message, innerException)
+        {
+        }
+
+        /// <summary>
+        /// Initializes a new instance of the
+        /// <see cref="BrokenBarrierException"/> class with serialized data.
+        /// </summary>
+        /// <param name="info">
+        /// The <see cref="SerializationInfo"/> that holds the serialized
+        /// object data about the exception being thrown.
+        /// </param>
+        /// <param name="context">
+        /// The <see cref="StreamingContext"/> that contains contextual
+        /// information about the source or destination.
+        /// </param>
+        protected BrokenBarrierException(SerializationInfo info, StreamingContext context)
+            : base(info, context)
+        {
+        }
+    }
+}

Cineraria.Concurrency/BusyWaitBuffer.cs

+// -----------------------------------------------------------------------
+// <copyright file="BusyWaitBuffer.cs">
+//     Copyright (c) Rhys 2012-03-08. All rights reserved.
+// </copyright>
+// -----------------------------------------------------------------------
+
+namespace Cineraria.Concurrency
+{
+    using System.Collections.Generic;
+    using System.Threading;
+
+    /// <summary>
+    /// A thread-safe generic buffer that loops when empty.
+    /// </summary>
+    /// <typeparam name="T">The type stored in the buffer.</typeparam>
+    public class BusyWaitBuffer<T> : IBuffer<T>
+    {
+        /// <summary>
+        /// The underlying queue.
+        /// </summary>
+        private readonly Queue<T> _queue = new Queue<T>();
+
+        /// <summary>
+        /// Object used for lock() blocks.
+        /// </summary>
+        /// <remarks>See http://stackoverflow.com/questions/251391/why-is-lockthis-bad </remarks>
+        private readonly object _syncRoot = new object();
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="BusyWaitBuffer&lt;T&gt;"/> class.
+        /// </summary>
+        public BusyWaitBuffer()
+        {
+        }
+
+        /// <summary>
+        /// Puts the specified item into the buffer.
+        /// </summary>
+        /// <param name="item">The item.</param>
+        public void Put(T item)
+        {
+            lock (this._syncRoot)
+            {
+                this._queue.Enqueue(item);
+            }
+        }
+
+        /// <summary>
+        /// Takes an item from the buffer. If empty, loops until it is not.
+        /// </summary>
+        /// <returns>The item.</returns>
+        public T Take()
+        {
+            while (true)
+            {
+                lock (this._syncRoot)
+                {
+                    if (this._queue.Count > 0)
+                    {
+                        return this._queue.Dequeue();
+                    }
+                }
+            }
+        }
+    }
+}

Cineraria.Concurrency/Channel.cs

+// -----------------------------------------------------------------------
+// <copyright file="Channel.cs">
+//     Copyright (c) Rhys 2012-03-08. All rights reserved.
+// </copyright>
+// -----------------------------------------------------------------------
+namespace Cineraria.Concurrency
+{
+    using System.Collections.Generic;
+    using ThreadInterruptedException = System.Threading.ThreadInterruptedException;
+
+    /// <summary>
+    /// A thread-safe generic channel.
+    /// </summary>
+    /// <typeparam name="T">The type stored in the channel.</typeparam>
+    public class Channel<T> : IBuffer<T>
+    {
+        /// <summary>
+        /// A semaphore representing permission to take an item.
+        /// </summary>
+        private readonly Semaphore _takePermission = new Semaphore();
+
+        /// <summary>
+        /// The underlying queue.
+        /// </summary>
+        private readonly Queue<T> _queue = new Queue<T>();
+
+        /// <summary>
+        /// Object used for lock() blocks.
+        /// </summary>
+        /// <remarks>See http://stackoverflow.com/questions/251391/why-is-lockthis-bad </remarks>
+        private readonly object _syncRoot = new object();
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="Channel&lt;T&gt;"/> class.
+        /// </summary>
+        public Channel()
+        {
+        }
+
+        /// <summary>
+        /// Puts the specified item into the channel.
+        /// </summary>
+        /// <param name="item">The item.</param>
+        public void Put(T item)
+        {
+            this.Offer(item, -1);
+        }
+
+        /// <summary>
+        /// Attempts to put the specified item into the channel, waiting a maximum of
+        /// <paramref name="milliseconds"/> before giving up.
+        /// </summary>
+        /// <param name="item">The item to put.</param>
+        /// <param name="milliseconds">
+        /// The maximum number of milliseconds to wait before giving up.
+        /// </param>
+        /// <returns>true if the item was put, false otherwise.</returns>
+        public virtual bool Offer(T item, int milliseconds)
+        {
+            lock (this._syncRoot)
+            {
+                this._queue.Enqueue(item);
+            }
+
+            this._takePermission.ForceRelease();
+
+            return true;
+        }
+
+        /// <summary>
+        /// Takes an item from the channel.
+        /// </summary>
+        /// <returns>The item.</returns>
+        public T Take()
+        {
+            T result;
+            this.Poll(out result, -1);
+            return result;
+        }
+
+        /// <summary>
+        /// Attempts to take an item from the channel, waiting a maximum of
+        /// <paramref name="milliseconds"/> before giving up.
+        /// </summary>
+        /// <param name="item">The item taken.</param>
+        /// <param name="milliseconds">
+        /// The maximum number of milliseconds to wait before giving up.
+        /// </param>
+        /// <returns>true if a item was taken, false otherwise.</returns>
+        public virtual bool Poll(out T item, int milliseconds)
+        {
+            if (this._takePermission.Attempt(milliseconds))
+            {
+                try
+                {
+                    lock (this._syncRoot)
+                    {
+                        item = this._queue.Dequeue();
+                        return true;
+                    }
+                }
+                catch (ThreadInterruptedException)
+                {
+                    this._takePermission.ForceRelease();
+                    throw;
+                }
+            }
+
+            item = default(T);
+            return false;
+        }
+    }
+}

Cineraria.Concurrency/Cineraria.Concurrency.csproj

+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" DefaultTargets="Build">
+  <PropertyGroup>
+    <ProjectGuid>{09217AE6-3929-4E8B-BF1C-495C25DADF79}</ProjectGuid>
+    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+    <Platform Condition=" '$(Platform)' == '' ">x86</Platform>
+    <OutputType>Library</OutputType>
+    <RootNamespace>Cineraria.Concurrency</RootNamespace>
+    <AssemblyName>Cineraria.Concurrency</AssemblyName>
+    <TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
+    <TargetFrameworkProfile>Client</TargetFrameworkProfile>
+    <AppDesignerFolder>Properties</AppDesignerFolder>
+    <DelaySign>False</DelaySign>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Platform)' == 'x86' ">
+    <PlatformTarget>x86</PlatformTarget>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
+    <OutputPath>bin\Debug\</OutputPath>
+    <DebugSymbols>True</DebugSymbols>
+    <DebugType>Full</DebugType>
+    <Optimize>False</Optimize>
+    <CheckForOverflowUnderflow>True</CheckForOverflowUnderflow>
+    <DefineConstants>DEBUG;TRACE</DefineConstants>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)' == 'Release' ">
+    <OutputPath>bin\Release\</OutputPath>
+    <DebugSymbols>False</DebugSymbols>
+    <DebugType>None</DebugType>
+    <Optimize>True</Optimize>
+    <CheckForOverflowUnderflow>False</CheckForOverflowUnderflow>
+    <DefineConstants>TRACE</DefineConstants>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x86'">
+    <CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
+    <RunCodeAnalysis>true</RunCodeAnalysis>
+    <DocumentationFile>bin\Debug\Cineraria.Concurrency.xml</DocumentationFile>
+  </PropertyGroup>
+  <PropertyGroup>
+    <SignAssembly>true</SignAssembly>
+  </PropertyGroup>
+  <PropertyGroup>
+    <AssemblyOriginatorKeyFile>Cineraria.pfx</AssemblyOriginatorKeyFile>
+  </PropertyGroup>
+  <ItemGroup>
+    <Reference Include="System" />
+  </ItemGroup>
+  <ItemGroup>
+    <Compile Include="Barrier.cs" />
+    <Compile Include="BorkBuffer.cs" />
+    <Compile Include="BoundedChannel.cs" />
+    <Compile Include="BrokenBarrierException.cs" />
+    <Compile Include="BusyWaitBuffer.cs" />
+    <Compile Include="Channel.cs" />
+    <Compile Include="FifoSemaphore.cs" />
+    <Compile Include="GuardedBuffer.cs" />
+    <Compile Include="IBuffer.cs" />
+    <Compile Include="IReaderWriterLock.cs" />
+    <Compile Include="ISync.cs" />
+    <Compile Include="Latch.cs" />
+    <Compile Include="Lightswitch.cs" />
+    <Compile Include="Mutex.cs" />
+    <Compile Include="PairRendezvous.cs" />
+    <Compile Include="Properties\AssemblyInfo.cs" />
+    <Compile Include="ReaderPriorityWriterLock.cs" />
+    <Compile Include="ReaderWriterLock.cs" />
+    <Compile Include="ReaderWriterPriorityLock.cs" />
+    <Compile Include="Rendezvous.cs" />
+    <Compile Include="Semaphore.cs" />
+    <Compile Include="StrongSemaphore.cs" />
+    <Compile Include="ThreadGroup.cs" />
+  </ItemGroup>
+  <ItemGroup>
+    <None Include="Cineraria.pfx" />
+  </ItemGroup>
+  <ItemGroup>
+    <ProjectReference Include="..\Cineraria.Convenience\Cineraria.Convenience.csproj">
+      <Project>{EEE8C93C-4F05-430F-85AA-0D4E8C508F7B}</Project>
+      <Name>Cineraria.Convenience</Name>
+    </ProjectReference>
+  </ItemGroup>
+  <ItemGroup>
+    <CodeAnalysisDictionary Include="CustomDictionary.xml" />
+  </ItemGroup>
+  <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.Targets" />
+</Project>

Cineraria.Concurrency/CustomDictionary.xml

+<?xml version="1.0" encoding="utf-8" ?>
+<Dictionary>
+  <Words>
+    <Recognized>
+      <Word>Lightswitch</Word>
+    </Recognized>
+  </Words>
+</Dictionary>

Cineraria.Concurrency/FifoSemaphore.cs

+// -----------------------------------------------------------------------
+// <copyright file="FIFOSemaphore.cs">
+//     Copyright (c) Rhys 22/03/2012. All rights reserved.
+// </copyright>
+// -----------------------------------------------------------------------
+
+namespace Cineraria.Concurrency
+{
+    using System;
+    using System.Collections.Generic;
+
+    /// <summary>
+    /// A first-in-first-out semaphore.
+    /// </summary>
+    public class FifoSemaphore : ISync
+    {
+        /// <summary>
+        /// Object used for lock() blocks.
+        /// </summary>
+        private readonly object _syncRoot = new object();
+
+        /// <summary>
+        /// A queue of semaphores, one for each thread waiting on this <see cref="FifoSemaphore"/>.
+        /// </summary>
+        private readonly Queue<Semaphore> _queue = new Queue<Semaphore>();
+
+        /// <summary>
+        /// The number of positive logical tokens.
+        /// </summary>
+        private int _tokens = 0;
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="FifoSemaphore"/> class with 0 logical tokens.
+        /// </summary>
+        public FifoSemaphore()
+            : this(0)
+        {
+        }
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="FifoSemaphore"/> class with the specified
+        /// number of logical tokens.
+        /// </summary>
+        /// <param name="tokens">The tokens.</param>
+        public FifoSemaphore(int tokens)
+        {
+            this._tokens = tokens;
+        }
+
+        /// <summary>
+        /// Acquires a logical token.
+        /// </summary>
+        public void Acquire()
+        {
+            Semaphore goPermission = null;
+            lock (this._syncRoot)
+            {
+                if (this._tokens > 0)
+                {
+                    this._tokens--;
+                }
+                else
+                {
+                    goPermission = new Semaphore(0);
+                    this._queue.Enqueue(goPermission);
+                }
+            }
+
+            if (goPermission != null)
+            {
+                goPermission.Acquire();
+            }
+        }
+
+        /// <summary>
+        /// Releases a logical token.
+        /// </summary>
+        public void Release()
+        {
+            this.Release(1);
+        }
+
+        /// <summary>
+        /// Releases the specified number of logical tokens.
+        /// </summary>
+        /// <param name="tokens">The number of logical tokens to release.</param>
+        public void Release(int tokens)
+        {
+            if (tokens <= 0)
+            {
+                throw new ArgumentOutOfRangeException("tokens");
+            }
+
+            lock (this._syncRoot)
+            {
+                for (int i = 0; i < tokens; i++)
+                {
+                    if (this._queue.Count > 0)
+                    {
+                        Semaphore otherThread = this._queue.Dequeue();
+                        otherThread.Release();
+                    }
+                    else
+                    {
+                        this._tokens++;
+                    }
+                }
+            }
+        }
+    }
+}

Cineraria.Concurrency/GuardedBuffer.cs

+// -----------------------------------------------------------------------
+// <copyright file="GuardedBuffer.cs">
+//     Copyright (c) Rhys 2012-03-08. All rights reserved.
+// </copyright>
+// -----------------------------------------------------------------------
+
+namespace Cineraria.Concurrency
+{
+    using System.Collections.Generic;
+    using System.Threading;
+
+    /// <summary>
+    /// A thread-safe generic buffer that waits when empty.
+    /// </summary>
+    /// <typeparam name="T">The type stored in the buffer.</typeparam>
+    public class GuardedBuffer<T> : IBuffer<T>
+    {
+        /// <summary>
+        /// The underlying queue.
+        /// </summary>
+        private readonly Queue<T> _queue = new Queue<T>();
+
+        /// <summary>
+        /// Object used for lock() blocks.
+        /// </summary>
+        /// <remarks>See http://stackoverflow.com/questions/251391/why-is-lockthis-bad </remarks>
+        private readonly object _syncRoot = new object();
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="GuardedBuffer&lt;T&gt;"/> class.
+        /// </summary>
+        public GuardedBuffer()
+        {
+        }
+
+        /// <summary>
+        /// Puts the specified item into the buffer.
+        /// </summary>
+        /// <param name="item">The item.</param>
+        public void Put(T item)
+        {
+            lock (this._syncRoot)
+            {
+                this._queue.Enqueue(item);
+                Monitor.PulseAll(this._syncRoot);
+            }
+        }
+
+        /// <summary>
+        /// Takes an item from the buffer. If empty, waits/sleeps until it is not.
+        /// </summary>
+        /// <returns>The item.</returns>
+        public T Take()
+        {
+            lock (this._syncRoot)
+            {
+                while (this._queue.Count <= 0)
+                {
+                    Monitor.Wait(this._syncRoot);
+                }
+
+                return this._queue.Dequeue();
+            }
+        }
+    }
+}

Cineraria.Concurrency/IBuffer.cs

+// -----------------------------------------------------------------------
+// <copyright file="IBuffer.cs">
+//     Copyright (c) Rhys 2012-03-08. All rights reserved.
+// </copyright>
+// -----------------------------------------------------------------------
+
+namespace Cineraria.Concurrency
+{
+    /// <summary>
+    /// A thread-safe generic buffer.
+    /// </summary>
+    /// <typeparam name="T">The type stored in the buffer.</typeparam>
+    public interface IBuffer<T>
+    {
+        /// <summary>
+        /// Puts the specified item into the buffer.
+        /// </summary>
+        /// <param name="item">The item.</param>
+        void Put(T item);
+
+        /// <summary>
+        /// Takes an item from the buffer.
+        /// </summary>
+        /// <returns>The item.</returns>
+        T Take();
+    }
+}

Cineraria.Concurrency/IReaderWriterLock.cs

+// -----------------------------------------------------------------------
+// <copyright file="IReaderWriterLock.cs">
+//     Copyright (c) Rhys 22/03/2012. All rights reserved.
+// </copyright>
+// -----------------------------------------------------------------------
+
+namespace Cineraria.Concurrency
+{
+    /// <summary>
+    /// A reader/writer lock.
+    /// </summary>
+    public interface IReaderWriterLock
+    {
+        /// <summary>
+        /// Acquires permission to read.
+        /// </summary>
+        void AcquireReader();
+
+        /// <summary>
+        /// Acquires permission to write.
+        /// </summary>
+        void AcquireWriter();
+
+        /// <summary>
+        /// Releases permission to read.
+        /// </summary>
+        void ReleaseReader();
+
+        /// <summary>
+        /// Releases permission to write.
+        /// </summary>
+        void ReleaseWriter();
+    }
+}

Cineraria.Concurrency/ISync.cs

+// -----------------------------------------------------------------------
+// <copyright file="ISync.cs">
+//     Copyright (c) Rhys 2012-03-08. All rights reserved.
+// </copyright>
+// -----------------------------------------------------------------------
+
+namespace Cineraria.Concurrency
+{
+    /// <summary>
+    /// A semaphore.
+    /// </summary>
+    public interface ISync
+    {
+        /// <summary>
+        /// Acquires a logical token.
+        /// </summary>
+        void Acquire();
+
+        /// <summary>
+        /// Releases a logical token.
+        /// </summary>
+        void Release();
+    }
+}

Cineraria.Concurrency/Latch.cs

+// -----------------------------------------------------------------------
+// <copyright file="Latch.cs">
+//     Copyright (c) Rhys 2012-03-15. All rights reserved.
+// </copyright>
+// -----------------------------------------------------------------------
+
+namespace Cineraria.Concurrency
+{
+    /// <summary>
+    /// A single-use thread latch mechanism.
+    /// </summary>
+    public class Latch : ISync
+    {
+        /// <summary>
+        /// A semaphore representing permission to continue through the latch.
+        /// </summary>
+        private Semaphore _goPermission = new Semaphore(0);
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="Latch"/> class.
+        /// </summary>
+        public Latch()
+        {
+        }
+
+        /// <summary>
+        /// Waits until the latch is opened.
+        /// </summary>
+        public void Acquire()
+        {
+            this._goPermission.Acquire();
+            this._goPermission.Release();
+        }
+
+        /// <summary>
+        /// Opens the latch.
+        /// </summary>
+        public void Release()
+        {
+            this._goPermission.Release();
+        }
+    }
+}

Cineraria.Concurrency/Lightswitch.cs

+// -----------------------------------------------------------------------
+// <copyright file="Lightswitch.cs">
+//     Copyright (c) Rhys 22/03/2012. All rights reserved.
+// </copyright>
+// -----------------------------------------------------------------------
+
+namespace Cineraria.Concurrency
+{
+    /// <summary>
+    /// Acquires the specified semaphore on first acquire and releases it on last release.
+    /// </summary>
+    public class Lightswitch : ISync
+    {
+        /// <summary>
+        /// Object used for lock() blocks.
+        /// </summary>
+        private readonly object _syncRoot = new object();
+
+        /// <summary>
+        /// The <see cref="ISync"/> object being "switched on and off".
+        /// </summary>
+        private readonly ISync _innerPermission;
+
+        /// <summary>
+        /// The number of threads that have acquired this <see cref="Lightswitch"/>.
+        /// </summary>
+        private int _count = 0;
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="Lightswitch"/> class with the specified
+        /// inner permission.
+        /// </summary>
+        /// <param name="innerPermission">The inner permission.</param>
+        public Lightswitch(ISync innerPermission)
+        {
+            this._innerPermission = innerPermission;
+        }
+
+        /// <summary>
+        /// Acquires a logical token. Will acquire inner permission if no other tokens
+        /// have been acquired.
+        /// </summary>
+        public void Acquire()
+        {
+            lock (this._syncRoot)
+            {
+                if (this._count == 0)
+                {
+                    this._innerPermission.Acquire();
+                }
+
+                this._count++;
+            }
+        }
+
+        /// <summary>
+        /// Releases a logical token. Will release inner permission if all other tokens
+        /// have been released.
+        /// </summary>
+        public void Release()
+        {
+            lock (this._syncRoot)
+            {
+                this._count--;
+                if (this._count == 0)
+                {
+                    this._innerPermission.Release();
+                }
+            }
+        }
+    }
+}

Cineraria.Concurrency/Mutex.cs

+// -----------------------------------------------------------------------
+// <copyright file="Mutex.cs">
+//     Copyright (c) Rhys 2012-03-15. All rights reserved.
+// </copyright>
+// -----------------------------------------------------------------------
+namespace Cineraria.Concurrency
+{
+    using System;
+
+    /// <summary>
+    /// A thread mutex mechanism.
+    /// </summary>
+    public class Mutex : Semaphore
+    {
+        /// <summary>
+        /// Initializes a new instance of the <see cref="Mutex"/> class with 1 logical tokens.
+        /// </summary>
+        public Mutex()
+            : this(1)
+        {
+        }
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="Mutex"/> class with the specified number
+        /// of logical tokens.
+        /// </summary>
+        /// <param name="tokens">The number of logical tokens to start with.</param>
+        /// <exception cref="ArgumentOutOfRangeException"><paramref name="tokens"/> must be 0 or 1.</exception>
+        public Mutex(int tokens)
+            : base(tokens)
+        {
+            if (tokens < 0 || tokens > 1)
+            {
+                throw new ArgumentOutOfRangeException("tokens");
+            }
+        }
+
+        /// <summary>
+        /// Releases the specified number of logical tokens.
+        /// </summary>
+        /// <param name="tokens">The number of logical tokens to release.</param>
+        /// <exception cref="ArgumentOutOfRangeException">tokens must be 1.</exception>
+        /// <exception cref="InvalidOperationException">Cannot release a mutex that's not held.</exception>
+        public override void Release(int tokens)
+        {
+            if (tokens != 1)
+            {
+                throw new ArgumentOutOfRangeException("tokens");
+            }
+
+            lock (this.SyncRoot)
+            {
+                if (this.TokenCount > 0)
+                {
+                    throw new InvalidOperationException("Cannot release a mutex that's not held.");
+                }
+                else
+                {
+                    base.Release(tokens);
+                }
+            }
+        }
+    }
+}

Cineraria.Concurrency/PairRendezvous.cs

+// -----------------------------------------------------------------------
+// <copyright file="PairRendezvous.cs">
+//     Copyright (c) Rhys 2012-03-15. All rights reserved.
+// </copyright>
+// -----------------------------------------------------------------------
+
+namespace Cineraria.Concurrency
+{
+    /// <summary>
+    /// A two thread rendezvous mechanism.
+    /// </summary>
+    /// <typeparam name="T">The type of item exchanged.</typeparam>
+    public class PairRendezvous<T>
+    {
+        /// <summary>
+        /// Object used for lock() blocks.
+        /// </summary>
+        /// <remarks>See http://stackoverflow.com/questions/251391/why-is-lockthis-bad </remarks>
+        private readonly object _syncRoot = new object();
+
+        /// <summary>
+        /// Turnstile to prevent threads racing through <see cref="Exchange(T)"/>.
+        /// </summary>
+        private Semaphore _turnstile = new Semaphore(1);
+
+        /// <summary>
+        /// A semaphore representing permission to continue with the exchange.
+        /// </summary>
+        private Semaphore _goPermission = new Semaphore(0);
+
+        /// <summary>
+        /// A value indicating whether the current thread is the first thread to begin the exchange.
+        /// </summary>
+        private bool _isFirst = true;
+
+        /// <summary>
+        /// The item held for exchange.
+        /// </summary>
+        private T _held;
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="PairRendezvous&lt;T&gt;"/> class.
+        /// </summary>
+        public PairRendezvous()
+        {
+        }
+
+        /// <summary>
+        /// Exchanges the specified item.
+        /// </summary>
+        /// <param name="item">The item to exchange.</param>
+        /// <returns>Another item.</returns>
+        public T Exchange(T item)
+        {
+            this._turnstile.Acquire();
+
+            lock (this._syncRoot)
+            {
+                if (this._isFirst)
+                {
+                    this._held = item;
+                    this._isFirst = false;
+                    this._turnstile.Release();
+                }
+                else
+                {
+                    T result = this._held;
+                    this._held = item;
+                    this._goPermission.Release();
+                    return result;
+                }
+            }
+
+            this._goPermission.Acquire();
+
+            lock (this._syncRoot)
+            {
+                this._isFirst = true;
+                this._turnstile.Release();
+                return this._held;
+            }
+        }
+    }
+}

Cineraria.Concurrency/Properties/AssemblyInfo.cs

+//<auto-generated />
+#region Using directives
+
+using System;
+using System.Reflection;
+using System.Runtime.InteropServices;
+
+#endregion
+
+// General Information about an assembly is controlled through the following
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyTitle("Cineraria.Concurrency")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("")]
+[assembly: AssemblyCopyright("Copyright © Rhys 2012")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// This sets the default COM visibility of types in the assembly to invisible.
+// If you need to expose a type to COM, use [ComVisible(true)] on that type.
+[assembly: ComVisible(false)]
+
+// The assembly version has following format :
+//
+// Major.Minor.Build.Revision
+//
+// You can specify all the values or you can use the default the Revision and
+// Build Numbers by using the '*' as shown below:
+[assembly: AssemblyVersion("0.1.*")]
+[assembly: CLSCompliant(true)]

Cineraria.Concurrency/ReaderPriorityWriterLock.cs

+// -----------------------------------------------------------------------
+// <copyright file="ReaderPriorityWriterLock.cs">
+//     Copyright (c) Rhys 22/03/2012. All rights reserved.
+// </copyright>
+// -----------------------------------------------------------------------
+
+namespace Cineraria.Concurrency
+{
+    /// <summary>
+    /// A reader-priority reader/writer lock.
+    /// </summary>
+    public class ReaderPriorityWriterLock : IReaderWriterLock
+    {
+        /// <summary>
+        /// Semaphore representing permission to write.
+        /// </summary>
+        private readonly Semaphore _writePermission = new Semaphore(1);
+
+        /// <summary>
+        /// Lightswitch representing permission to read.
+        /// </summary>
+        private readonly Lightswitch _readPermission;
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="ReaderPriorityWriterLock"/> class.
+        /// </summary>
+        public ReaderPriorityWriterLock()
+        {
+            this._readPermission = new Lightswitch(this._writePermission);
+        }
+
+        /// <summary>
+        /// Acquires permission to read.
+        /// </summary>
+        public void AcquireReader()
+        {
+            this._readPermission.Acquire();
+        }
+
+        /// <summary>
+        /// Releases permission to read.
+        /// </summary>
+        public void ReleaseReader()
+        {
+            this._readPermission.Release();
+        }
+
+        /// <summary>
+        /// Acquires permission to write.
+        /// </summary>
+        public void AcquireWriter()
+        {
+            this._writePermission.Acquire();
+        }
+
+        /// <summary>
+        /// Releases permission to write.
+        /// </summary>
+        public void ReleaseWriter()
+        {
+            this._writePermission.Release();
+        }
+    }
+}

Cineraria.Concurrency/ReaderWriterLock.cs

+// -----------------------------------------------------------------------
+// <copyright file="ReaderWriterLock.cs">
+//     Copyright (c) Rhys 22/03/2012. All rights reserved.
+// </copyright>
+// -----------------------------------------------------------------------
+
+namespace Cineraria.Concurrency
+{
+    /// <summary>
+    /// A neutral reader/writer lock.
+    /// </summary>
+    public class ReaderWriterLock : IReaderWriterLock
+    {
+        /// <summary>
+        /// A semaphore representing permission to read.
+        /// </summary>
+        private readonly Semaphore _writePermission = new Semaphore(1);
+
+        /// <summary>
+        /// A turnstile used to give writers and readers equal priority.
+        /// </summary>
+        private readonly Semaphore _turnstile = new Semaphore(1);
+
+        /// <summary>
+        /// A lightswitch representing permission to read.
+        /// </summary>
+        private readonly Lightswitch _readPermission;
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="ReaderWriterLock"/> class.
+        /// </summary>
+        public ReaderWriterLock()
+        {
+            this._readPermission = new Lightswitch(this._writePermission);
+        }
+
+        /// <summary>
+        /// Acquires permission to read.
+        /// </summary>
+        public void AcquireReader()
+        {
+            this._turnstile.Acquire();
+            this._turnstile.Release();
+            this._readPermission.Acquire();
+        }
+
+        /// <summary>
+        /// Releases permission to read.
+        /// </summary>
+        public void ReleaseReader()
+        {
+            this._readPermission.Release();
+        }
+
+        /// <summary>
+        /// Acquires permission to write.
+        /// </summary>
+        public void AcquireWriter()
+        {
+            this._turnstile.Acquire();
+            this._writePermission.Acquire();
+        }
+
+        /// <summary>
+        /// Releases permission to write.
+        /// </summary>
+        public void ReleaseWriter()
+        {
+            this._writePermission.Release();
+            this._turnstile.Release();
+        }
+    }
+}

Cineraria.Concurrency/ReaderWriterPriorityLock.cs

+// -----------------------------------------------------------------------
+// <copyright file="ReaderWriterPriorityLock.cs">
+//     Copyright (c) Rhys 22/03/2012. All rights reserved.
+// </copyright>
+// -----------------------------------------------------------------------
+
+namespace Cineraria.Concurrency
+{
+    /// <summary>
+    /// An writer-priority reader/writer lock.
+    /// </summary>
+    public class ReaderWriterPriorityLock : IReaderWriterLock
+    {
+        /// <summary>
+        /// A semaphore representing permission to write.
+        /// </summary>
+        private readonly Semaphore _writePermission = new Semaphore(1);
+
+        /// <summary>
+        /// A turnstile used by readers so they're locked out when writers are queued.
+        /// </summary>
+        private readonly Semaphore _turnstile = new Semaphore(1);
+
+        /// <summary>
+        /// A lightswitch representing permission to read.
+        /// </summary>
+        private readonly Lightswitch _readPermission;
+
+        /// <summary>
+        /// A turnstile used by writers to lock out readers when writers are queued.
+        /// </summary>
+        private readonly Lightswitch _writerTurnstile;
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="ReaderWriterPriorityLock"/> class.
+        /// </summary>
+        public ReaderWriterPriorityLock()
+        {
+            this._readPermission = new Lightswitch(this._writePermission);
+            this._writerTurnstile = new Lightswitch(this._turnstile);
+        }
+
+        /// <summary>
+        /// Acquires permission to read.
+        /// </summary>
+        public void AcquireReader()
+        {
+            this._turnstile.Acquire();
+            this._turnstile.Release();
+            this._readPermission.Acquire();
+        }
+
+        /// <summary>
+        /// Releases permission to read.
+        /// </summary>
+        public void ReleaseReader()
+        {
+            this._readPermission.Release();
+        }
+
+        /// <summary>
+        /// Acquires permission to write.
+        /// </summary>
+        public void AcquireWriter()
+        {
+            this._writerTurnstile.Acquire();
+            this._writePermission.Acquire();
+        }
+
+        /// <summary>
+        /// Releases permission to write.
+        /// </summary>
+        public void ReleaseWriter()
+        {
+            this._writePermission.Release();
+            this._writerTurnstile.Release();
+        }
+    }
+}

Cineraria.Concurrency/Rendezvous.cs

+// -----------------------------------------------------------------------
+// <copyright file="Rendezvous.cs">
+//     Copyright (c) Rhys 2012-03-15. All rights reserved.
+// </copyright>
+// -----------------------------------------------------------------------
+
+namespace Cineraria.Concurrency
+{
+    using System;
+
+    /// <summary>
+    /// A multi-thread rendezvous mechanism.
+    /// </summary>
+    /// <typeparam name="T">The type of item exchanged.</typeparam>
+    public class Rendezvous<T>
+    {
+        /// <summary>
+        /// Object used for lock() blocks.
+        /// </summary>
+        /// <remarks>See http://stackoverflow.com/questions/251391/why-is-lockthis-bad </remarks>
+        private readonly object _syncRoot = new object();
+
+        /// <summary>
+        /// Turnstile to prevent threads racing through <see cref="Exchange"/>.
+        /// </summary>
+        private readonly Semaphore _turnstile = new Semaphore(1);
+
+        /// <summary>
+        /// A semaphore representing permission to continue with the exchange.
+        /// </summary>
+        private readonly Semaphore _goPermission = new Semaphore(0);
+
+        /// <summary>
+        /// The number of threads that must begin the exchange process for the exhange to continue.
+        /// </summary>
+        private readonly int _threshold;
+
+        /// <summary>
+        /// An array of items being held for exchange.
+        /// </summary>
+        private readonly T[] _held;
+
+        /// <summary>
+        /// The number of threads that have begun the exchange process.
+        /// </summary>
+        private int _count = 0;
+
+        /// <summary>
+        /// Whether this rendezvous is broken.
+        /// </summary>
+        private bool _isBroken = false;
+
+        /// <summary>
+        /// Whether this rendezvous is open, ie. threshold was met and threads can leave.
+        /// </summary>
+        private bool _isOpen = false;
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="Rendezvous&lt;T&gt;"/> class.
+        /// </summary>
+        /// <param name="threshold">The number of threads that must begin the exchange process for the exhange to continue.</param>
+        public Rendezvous(int threshold)
+        {
+            this._threshold = threshold;
+            this._held = new T[threshold];
+        }
+
+        /// <summary>
+        /// Exchanges the specified item.
+        /// </summary>
+        /// <param name="item">The item to exchange.</param>
+        /// <param name="shuffle">
+        /// The method to invoke to shuffle the items being exchanged.
+        /// </param>
+        /// <param name="milliseconds">
+        /// The maximum number of milliseconds to wait before breaking this
+        /// rendezvous.
+        /// </param>
+        /// <returns>Another item.</returns>
+        /// <exception cref="ArgumentNullException">
+        /// <paramref name="shuffle"/> cannot be null.
+        /// </exception>
+        /// <exception cref="ArgumentOutOfRangeException">
+        /// <paramref name="milliseconds"/> must be positive or -1.
+        /// </exception>
+        public T Exchange(T item, Action<T[]> shuffle, int milliseconds)
+        {
+            if (shuffle == null)
+            {
+                throw new ArgumentNullException("shuffle");
+            }
+
+            this._turnstile.Acquire();
+
+            lock (this._syncRoot)
+            {
+                if (this._isBroken)
+                {
+                    this._turnstile.Release();
+                    throw new BrokenBarrierException();
+                }
+
+                this._held[this._count] = item;
+                this._count++;
+                if (this._count == this._threshold)
+                {
+                    shuffle(this._held);
+                    this._isOpen = true;
+                    this._goPermission.Release(this._threshold);
+                }
+                else
+                {
+                    this._turnstile.Release();
+                }
+            }
+
+            bool acquiredGoPermission = this._goPermission.Attempt(milliseconds);
+
+            lock (this._syncRoot)
+            {
+                this._count--;
+                if (!acquiredGoPermission && this._isOpen)
+                {
+                    this._goPermission.Acquire();
+                    acquiredGoPermission = true;
+                }
+
+                if (acquiredGoPermission)
+                {
+                    if (this._count == 0)
+                    {
+                        this._isOpen = false;
+                        this._turnstile.Release();
+                    }
+
+                    if (this._isBroken)
+                    {
+                        throw new BrokenBarrierException();
+                    }
+
+                    return this._held[this._count];
+                }
+                else
+                {
+                    this._isBroken = true;
+                    this._goPermission.Release(this._count);
+                    this._turnstile.Release();
+                    throw new BrokenBarrierException();
+                }
+            }
+        }
+    }
+}

Cineraria.Concurrency/Semaphore.cs

+// -----------------------------------------------------------------------
+// <copyright file="Semaphore.cs">
+//     Copyright (c) Rhys 2012-03-08. All rights reserved.
+// </copyright>
+// -----------------------------------------------------------------------
+
+namespace Cineraria.Concurrency
+{
+    using System;
+    using System.Threading;
+
+    /// <summary>
+    /// A semaphore.
+    /// </summary>
+    public class Semaphore : ISync
+    {
+        /// <summary>
+        /// Object used for lock() blocks.
+        /// </summary>
+        private readonly object _syncRoot = new object();
+
+        /// <summary>
+        /// The number of logical tokens available.
+        /// </summary>
+        private int _tokenCount;
+
+        /// <summary>
+        /// The number of threads waiting.
+        /// </summary>
+        private int _waitingThreads;
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="Semaphore"/> class with 0 logical tokens.
+        /// </summary>
+        public Semaphore()
+            : this(0)
+        {
+        }
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="Semaphore"/> class with the specified number
+        /// of logical tokens.
+        /// </summary>
+        /// <param name="tokens">The number of logical tokens to start with.</param>
+        public Semaphore(int tokens)
+        {
+            this._tokenCount = tokens;
+            this._waitingThreads = 0;
+        }
+
+        /// <summary>
+        /// Gets the object used for lock() blocks.
+        /// </summary>
+        /// <remarks>See http://stackoverflow.com/questions/251391/why-is-lockthis-bad </remarks>
+        protected object SyncRoot
+        {
+            get { return this._syncRoot; }
+        }
+
+        /// <summary>
+        /// Gets the number of logical tokens available.
+        /// </summary>
+        protected int TokenCount
+        {
+            get { return this._tokenCount; }
+        }
+
+        /// <summary>
+        /// Acquires a logical token.
+        /// </summary>
+        public void Acquire()
+        {
+            this.Attempt(-1);
+        }
+
+        /// <summary>
+        /// Waits a maximum of <paramref name="milliseconds"/> to acquire a
+        /// logical token.
+        /// </summary>
+        /// <param name="milliseconds">
+        /// The maximum number of milliseconds to wait to acquire a logical
+        /// token.
+        /// </param>
+        /// <returns>
+        /// true if a logical token was acquired, false otherwise.
+        /// </returns>
+        /// <exception cref="ArgumentOutOfRangeException">
+        /// <paramref name="milliseconds"/> must be positive or -1.
+        /// </exception>
+        public bool Attempt(int milliseconds)
+        {
+            if (milliseconds < -1 || milliseconds == 0)
+            {
+                throw new ArgumentOutOfRangeException("milliseconds");
+            }
+
+            DateTime endTime = DateTime.Now.AddMilliseconds(milliseconds);
+            lock (this.SyncRoot)
+            {
+                if (this._tokenCount > 0)
+                {
+                    this._tokenCount--;
+                    return true;
+                }
+
+                int timeLeft;
+                if (milliseconds == -1)
+                {
+                    timeLeft = -1;
+                }
+                else
+                {
+                     timeLeft = (int)(endTime - DateTime.Now).TotalMilliseconds;
+                }
+
+                this._waitingThreads++;
+                try
+                {
+                    while (timeLeft > 0 || milliseconds == -1)
+                    {
+                        try
+                        {
+                            Monitor.Wait(this._syncRoot, timeLeft);
+                        }
+                        catch (ThreadInterruptedException)
+                        {
+                            Monitor.Pulse(this._syncRoot);
+                            throw;
+                        }
+
+                        if (this._tokenCount > 0)
+                        {
+                            this._tokenCount--;
+                            return true;
+                        }
+                        else if (milliseconds != -1)
+                        {
+                            timeLeft = (int)(endTime - DateTime.Now).TotalMilliseconds;
+                        }
+                    }
+
+                    return false;
+                }
+                finally
+                {
+                    this._waitingThreads--;
+                }
+            }
+        }
+
+        /// <summary>
+        /// Releases a logical token.
+        /// </summary>
+        public void Release()
+        {
+            this.Release(1);
+        }
+
+        /// <summary>
+        /// Releases the specified number of logical tokens.
+        /// </summary>
+        /// <param name="tokens">The number of logical tokens to release.</param>
+        /// <exception cref="ArgumentOutOfRangeException">tokens must be a positive number.</exception>
+        public virtual void Release(int tokens)
+        {
+            if (tokens <= 0)
+            {
+                throw new ArgumentOutOfRangeException("tokens");
+            }
+
+            lock (this.SyncRoot)
+            {
+                this._tokenCount += tokens;
+                Monitor.PulseAll(this._syncRoot); // TODO: use Pulse (checks: waiting <= tokens (PA), waiting > tokens (P(tokens)), !waiting (noop))
+            }
+        }
+
+        /// <summary>
+        /// Releases a logical token in an uninterruptable manner.
+        /// </summary>
+        public void ForceRelease()
+        {
+            this.ForceRelease(1);
+        }
+
+        /// <summary>
+        /// Releases the specified number of logical tokens in an
+        /// uninterruptable manner.
+        /// </summary>
+        /// <param name="tokens">
+        /// The number of logical tokens to release.
+        /// </param>
+        public void ForceRelease(int tokens)
+        {
+            bool interrupted = false;
+            while (true)
+            {
+                try
+                {
+                    this.Release(tokens);
+                    if (interrupted)
+                    {
+                        Thread.CurrentThread.Interrupt();
+                    }
+
+                    return;
+                }
+                catch (ThreadInterruptedException)
+                {
+                    interrupted = true;
+                }
+            }
+        }
+    }
+}

Cineraria.Concurrency/Settings.StyleCop

+<StyleCopSettings Version="105">
+  <Analyzers>
+    <Analyzer AnalyzerId="StyleCop.CSharp.DocumentationRules">
+      <Rules>
+        <Rule Name="FileHeaderMustHaveValidCompanyText">
+          <RuleSettings>
+            <BooleanProperty Name="Enabled">False</BooleanProperty>
+          </RuleSettings>
+        </Rule>
+      </Rules>
+      <AnalyzerSettings />
+    </Analyzer>
+    <Analyzer AnalyzerId="StyleCop.CSharp.NamingRules">
+      <Rules>
+        <Rule Name="FieldNamesMustNotBeginWithUnderscore">
+          <RuleSettings>
+            <BooleanProperty Name="Enabled">False</BooleanProperty>
+          </RuleSettings>
+        </Rule>
+        <Rule Name="FieldNamesMustNotContainUnderscore">
+          <RuleSettings>
+            <BooleanProperty Name="Enabled">False</BooleanProperty>
+          </RuleSettings>