gpt4 book ai didi

c# - Monitor.Pulse & Wait - 意外行为

转载 作者:太空狗 更新时间:2023-10-29 22:33:25 25 4
gpt4 key购买 nike

http://www.codeproject.com/Articles/28785/Thread-synchronization-Wait-and-Pulse-demystified

Queues:

The ready queue is the collection of threads that are waiting for aparticular lock. The Monitor.Wait methods introduce another queue: thewaiting queue. This is required as waiting for a Pulse is distinctfrom waiting to acquire a lock. Like the ready queue, the waitingqueue is FIFO.

Recommended pattern:

These queues can lead to unexpected behaviour. When a Pulse occurs,the head of the waiting queue is released and is added to the readyqueue. However, if there are other threads in the ready queue, theywill acquire the lock before the thread that was released. This is aproblem, because the thread that acquires the lock can alter the statethat the pulsed thread relies on. The solution is to use a whilecondition inside the lock statement

*Q = 队列。

据我所知,当我调用 Pulse 时,它会在结束前做两件事。首先,它从等待 Q 中移除一个线程到就绪 Q。其次,它让就绪 Q 中的一个线程(不知道那个线程是谁)获得锁;它不关心谁获得了锁(来自等待 Q 的线程或出于某种原因处于就绪 Q 中的线程)。

如果我是对的,那么 为什么Monitor.Wait 之前放置一个 while 有助于解决问题(问题 -即使来自等待 Q 的线程未获得锁,脉冲也会结束)?

一个请告诉我关于 Monitor.Pulse 的用途是否正确。

B为什么我需要在 Monitor.Wait 之前放置一个 while

答案的完整代码如下:

class Program
{
static Queue<int> queue = new Queue<int>();
static object someMonitor = new object();

static void Main(string[] args)
{
Thread Thread1 = new Thread(WorkAlltheTime);
Thread1.Name = "Thread1";
Thread Thread2 = new Thread(WorkAlltheTime);
Thread2.Name = "Thread2";
Thread Thread3 = new Thread(WorkOnce);
Thread3.Name = "Thread3";
Thread1.Start();
Thread2.Start();
Thread.Sleep(1000);
Thread3.Start();
Console.ReadLine();
}

static void WorkAlltheTime()
{
Console.WriteLine("Came in to Ready Q: " + Thread.CurrentThread.Name);
lock (someMonitor)
{
Console.WriteLine("Came out from Ready Q: " + Thread.CurrentThread.Name);
// Broken!
while (queue.Count == 0)
{
Console.WriteLine("Came in to Waiting Q: " + Thread.CurrentThread.Name);
Monitor.Wait(someMonitor);
Console.WriteLine("Came out from Waiting Q: " + Thread.CurrentThread.Name);
}
queue.Dequeue();
Console.WriteLine("Thread: "+Thread.CurrentThread.Name+" Pulled Out");
}
}

static void WorkOnce()
{
lock (someMonitor)
{
queue.Enqueue(1);
Monitor.Pulse(someMonitor);
}
}
}

最佳答案

想象一下,您正在尝试编写一个生产者/消费者队列 - 您每次生产一个项目时都Pulse,而消费者需要等待直到有一个项目要消费。你会这样写代码:

Foo item;
lock(someMonitor)
{
while (queue.Count == 0)
{
Monitor.Wait(someMonitor);
}
item = queue.Dequeue();
}
// Use the item

假设您没有 while 循环,而是写:

Foo item;
lock(someMonitor)
{
// Broken!
if (queue.Count == 0)
{
Monitor.Wait(someMonitor);
}
item = queue.Dequeue();
}
// Use the item

现在假设您有一个线程已经在等待,然后另一个线程就在锁定语句之前......然后生产者向监视器发出脉冲(当然,并将一个项目添加到队列中)。

到那时,还没有获得锁的线程将第一个获得锁是完全可行的......此时“等待”线程获得锁时,队列将再次为空。只有一个 if 语句,没有循环,当队列为空时,您最终会出列,这将失败。

使用 while 循环,您将再次等待,直到生成下一个项目,这才是您真正想要的。

关于c# - Monitor.Pulse & Wait - 意外行为,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12121151/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com