hoo*_*law 4 c# synchronization thread-safety
我在C#中遇到了一些线程同步问题.我有一个共享对象,它被两个线程操纵,我使用lock()访问了互斥的对象,但我也希望根据共享对象的状态阻塞每个线程.当对象为空时特别阻塞线程A,当对象满时阻塞线程B,当对象状态改变时让另一个线程发出阻塞线程信号.
我尝试使用ManualResetEvent执行此操作,但遇到竞争条件,其中线程B将检测对象已满,移至WaitOne,并且线程A将进入并清空对象(每次访问都发出MRE信号,并阻止自身一次在线程A命中WaitOne之前,对象是空的,这意味着线程A正在等待线程未满,即使它不是.
我想如果我可以调用像'SignalAndWaitOne'这样的函数,那么在等待之前它会原子地发出信号,它会阻止这种竞争条件吗?
谢谢!
执行此操作的典型方法是使用Monitor.Enter,Monitor.Wait和Monitor.Pulse来控制对共享队列的访问.草图:
shared object sync = new object()
shared Queue q = new Queue()
Producer()
Enter(sync)
// This blocks until the lock is acquired
while(true)
while(q.IsFull)
Wait(sync)
// this releases the lock and blocks the thread
// until the lock is acquired again
// We have the lock and the queue is not full.
q.Enqueue(something)
Pulse(sync)
// This puts the waiting consumer thread to the head of the list of
// threads to be woken up when this thread releases the lock
Consumer()
Enter(sync)
// This blocks until the lock is acquired
while(true)
while(q.IsEmpty)
Wait(sync)
// this releases the lock and blocks the thread
// until the lock is acquired again
// We have the lock and the queue is not empty.
q.Dequeue()
Pulse(sync)
// This puts the waiting producer thread to the head of the list of
// threads to be woken up when this thread releases the lock
Run Code Online (Sandbox Code Playgroud)
A BlockingCollection已由.NET 4.0提供.
如果您使用的是早期版本,则可以Monitor直接使用该类.
编辑:以下代码完全未经测试,并且不处理maxCount小(<= 2)的值.它也没有任何超时或取消的规定:
public sealed class BlockingList<T>
{
private readonly List<T> data;
private readonly int maxCount;
public BlockingList(int maxCount)
{
this.data = new List<T>();
this.maxCount = maxCount;
}
public void Add(T item)
{
lock (data)
{
// Wait until the collection is not full.
while (data.Count == maxCount)
Monitor.Wait(data);
// Add our item.
data.Add(item);
// If the collection is no longer empty, signal waiting threads.
if (data.Count == 1)
Monitor.PulseAll(data);
}
}
public T Remove()
{
lock (data)
{
// Wait until the collection is not empty.
while (data.Count == 0)
Monitor.Wait(data);
// Remove our item.
T ret = data.RemoveAt(data.Count - 1);
// If the collection is no longer full, signal waiting threads.
if (data.Count == maxCount - 1)
Monitor.PulseAll(data);
}
}
}
Run Code Online (Sandbox Code Playgroud)