http://www.codeproject.com/Articles/28785/Thread-synchronization-Wait-and-Pulse-demystifiedMonitor.Pulse & Chờ - Hành vi bất ngờ
Queues:
Hàng đợi sẵn sàng là bộ sưu tập các chủ đề đang chờ đợi một khóa đặc biệt . Các phương thức Monitor.Wait giới thiệu một hàng đợi khác: hàng chờ đợi . Điều này là bắt buộc khi đợi Pulse khác biệt khi chờ để lấy khóa. Giống như hàng đợi sẵn sàng, hàng chờ đợi là FIFO.
Mẫu được đề xuất:
Những hàng đợi này có thể dẫn đến hành vi không mong muốn. Khi xảy ra xung, người đứng đầu hàng đợi đang chờ được phát hành và được thêm vào hàng đợi sẵn sàng . Tuy nhiên, nếu có các chủ đề khác trong hàng đợi sẵn sàng, chúng sẽ lấy khóa trước khi luồng được giải phóng. Đây là một vấn đề , bởi vì các chủ đề mà mua lại các khóa có thể làm thay đổi trạng thái mà các chủ đề xung dựa vào. Giải pháp là sử dụng một điều kiện trong khi trong tuyên bố khóa
* Q = Hàng đợi.
Bằng cách đó, tôi hiểu rằng khi tôi gọi Pulse
, nó sẽ làm 2 việc trước khi kết thúc. Thứ nhất, nó loại bỏ một sợi từ Q chờ đợi đến Q. sẵn sàng Thứ hai, nó cho phép một luồng (mà không biết ai là luồng đó) trong Ready Q có khóa; nó không quan tâm ai mua lại khóa (chủ đề đến từ sự chờ đợi Q hoặc một chủ đề trong Q sẵn sàng vì một lý do nào đó).
Nếu tôi đúng về điều đó thì tại sao được đặt một while
trước Monitor.Wait
giúp khắc phục vấn đề (vấn đề - xung kết thúc ngay cả khi chủ đề đến từ chờ đợi Q không có được các khóa)?
A. Hãy cho tôi biết nếu tôi đúng về mục đích của Monitor.Pulse
.
B. Tại sao tôi cần phải đặt một while
trước Monitor.Wait
Mã đầy đủ các câu trả lời dưới đây:
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);
}
}
}
Cảm ơn bạn, tôi đã viết mã đầy đủ của ví dụ của bạn và với lời giải thích của bạn tôi đã thử nghiệm nó 90 lần và tôi hoàn toàn hiểu ngay bây giờ. Cảm ơn Agian! –