Why does Monitor class keep 2 queues: “ready” and “waiting”?

空扰寡人 提交于 2019-12-23 06:13:15

问题


According to the MSDN:

The Monitor class consists of static (in C#) or Shared (in Visual Basic) methods that operate on an object that controls access to the critical section. The following information is maintained for each synchronized object:

  • A reference to the thread that currently holds the lock.

  • A reference to a ready queue, which contains the threads that are ready to obtain the lock.

  • A reference to a waiting queue, which contains the threads that are waiting for notification of a change in the state of the locked object.

And in this thread, the 2 queues are causing some subtle issue.

I think the root cause of the issue in above thread is there are 2 queues. If there's only ONE queue, whenever the Monitor.Pulse(), only one thread from that single queue can be scheduled to run. There's no way for more than one threads to be in ready state at the same time. So the issue should never happen.

So why does a Monitor keep 2 queues?


回答1:


I think you misunderstood that SO post. The problem was not caused by Monitor but by a genuine logic error in that OP's Queue class.

The Remove is a familiar pattern, it should use a while instead of an if:

lock (q)
{
    // if (q.Count == 0)
    while (q.Count == 0)
    {
        Monitor.Wait(q);
    }
    ... // use it, we are now sure that q.Count > 0
}

And then you may want an additional way (CancellationToken) to end the whole process.

A Monitor can have 2 sorts of waiting threads, the implementers chose to use 2 queues. Using 1 queue seems possible but that wouldn't change a thing. It would still allow only 1 thread to run at any time, so your understanding goes wrong at this point somehow.

What is happening is that a queued thread can have one of two states:

  • when a thread calls lock(q) and the lock is already taken, it is queued as Ready
  • when a thread calls Wait(q) it is queued as Waiting and needs a Pulse() to wake
  • When Pulse() is called, 1 Waiting thread is moved to the Ready state. But it will not immediately run, it will have to wait its turn. By definition, Pulse() can only be called when the lock is taken.
  • When the Pulsed thread is reactivated, the situation may have changed (ie, another thread consumed the data element).

The Pulse/Wait mechanism is sort of unreliable, when no thread is Waiting a Pulse goes unnoticed. You can't in general rely on Pulse/Wait for exact bookkeeping. And the contract of Monitor does not include fairness



来源:https://stackoverflow.com/questions/46295828/why-does-monitor-class-keep-2-queues-ready-and-waiting

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!