.NET provides the monitor class to synchronize access to a
resource.
(this is the class used when you use the lock() language
construct).
The Monitor makes sure that only one thread can access the
resource at
the same time. When the order in which the threads are
granted access
is not important, the monitor works great. However the
Monitor class
does _NOT_ guarantee FIFO behaviour.
Since for certain operations like in a production line, FIFO
behaviour
is an absolute requirement, I created a
SynchronizedQueue<T> class,
which does guarantee FIFO behaviour:
/// <summary>
/// This queue allows threads to queue for the use of a
resource
/// or an operation. Unfortunately, Monitors do *not*
guarantee
/// FIFO behaviour, so I've implemented this pretty queue.
///
/// Usage:
///
/// queue.Enter(this);
///
/// * perform operation *
///
/// queue.Release(this);
/// </summary>
/// <typeparam name="T"></typeparam>
public class SynchronizedQueue<T> where T : class {
Queue<T> _queue = new Queue<T>();
/// <summary>
/// Returns the element that currently can access the
resource
/// </summary>
public T CurrentElement {
get {
return _currentElement;
}
}
T _currentElement;
/// <summary>
/// Enters the queue and waits until access to the
resource is
granted.
/// </summary>
/// <param name="item"></param>
public void Enter(T item) {
lock(_queue) {
_queue.Enqueue(item);
}
while(_currentElement != item) {
lock(_queue) {
if(_currentElement == null) {
_currentElement = _queue.Dequeue();
}
}
Thread.Sleep(100);
}
}
/// <summary>
/// Releases the resource and exits the queue, thus
/// allowing the next in line to access the resource.
/// </summary>
/// <param name="item"></param>
public void Release(T item) {
if(_currentElement != item) {
throw new InvalidOperationException("Can't release
item '" + item +
", since it is not the current item.");
}
_currentElement = null;
}
/// <summary>
/// Returns a string representation of this queue
/// </summary>
/// <returns></returns>
public override string ToString() {
return "SyncQueue with " + _queue.Count +
" elements. Current
element: " + CurrentElement;
}
}
|