你能用C#线程同步进行原子信号和等待吗?

时间:2011-05-24 18:31:59

标签: c# synchronization thread-safety

我在C#中遇到线程同步问题。我有一个共享对象,它被两个线程操纵,我使用lock()访问了互斥的对象,但我也希望根据共享对象的状态阻塞每个线程。当对象为空时特别阻塞线程A,当对象填满时阻塞线程B,当对象状态改变时让另一个线程发出阻塞线程信号。

我尝试使用ManualResetEvent执行此操作,但遇到竞争条件,其中线程B将检测到对象已满,移至WaitOne,并且线程A将进入并清空对象(每次访问都发出MRE信号,并且一旦对象为空就阻塞自己)在线程A命中它的WaitOne之前,这意味着线程A正在等待线程未满,即使它不是。

我认为如果我可以调用类似'SignalAndWaitOne'的函数,那么在等待之前会原子地发出信号,这会阻止这种竞争条件吗?

谢谢!

2 个答案:

答案 0 :(得分:7)

执行此操作的典型方法是使用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

答案 1 :(得分:5)

.NET 4.0已经提供了BlockingCollection

如果您使用的是早期版本,则可以直接使用Monitor课程。

编辑:以下代码完全未经测试,并且不处理小({1}}小的值(< = 2)。它也没有任何超时或取消的规定:

maxCount