[英]What's the advantage of Monitor.Enter(object, ref bool) over Monitor.Enter(object)?
[英]Strange Behavior When Changing Exclusively Locked Object - Monitor.Enter(x)
我想看看如果您更改由Monitor.Enter()專門鎖定的對象的引用會發生什么。 如預期的那樣,引發了SynchronizationLockException。 但是令我驚訝的是,在引發異常之前,有多個線程通過了Monitor。
這是下面的代碼在做什么。
在這一點上,我預計會引發某種異常,但是直到Monitor.Exit(x)都不會發生。 真正奇怪的是,在引發異常之前,似乎有10到20個線程能夠通過鎖。 怎么發生的? 似乎不應該。 當然,更改排他鎖定對象的參考是不可以的。 我永遠不會在真實的代碼中做到這一點,但是仍然令我驚訝的是,其他線程已經超過了監視器。 你的意見?
using System;
using System.Threading;
namespace ThreadingPlayground
{
class Program
{
private int _value;
object x = new object();
ManualResetEvent _event = new ManualResetEvent(false);
static void Main()
{
Program p = new Program();
p.StartThreads();
Console.ReadLine();
}
private void StartThreads()
{
for(int i = 0;i<100;i++)
{
Thread t = new Thread(IncrementValue);
t.Start();
}
_event.Set();
}
private void IncrementValue()
{
WaitHandle.WaitAll(new WaitHandle[] {_event});
Monitor.Enter(x);
// Change the reference of the exclusively locked object. This
// allows other threads to enter, should this be possible?
x = Thread.CurrentThread.ManagedThreadId.ToString();
Console.WriteLine(++_value);
// throws a SynchronizationLockException
// but not until 10 - 20 more lines are written
Monitor.Exit(x);
}
}
}
您所看到的是預期的行為。 用於將引用傳遞給Monitor.Enter()
的實際變量沒有什么特別的。 更改引用不應阻止其他線程獲得排他鎖,因為變量具有新值,並且該引用未在任何地方鎖定。
您的問題與Exit
,因為調用Exit
的線程在傳入的引用上沒有排它鎖。另一個線程可能對此有鎖,但是您在其中執行的線程卻沒有鎖。
如您所知,這就是為什么最好總是使用永遠不會更改其引用的變量進行鎖定。 如果您的資源變量可能更改,請使用新的引用。
這足夠清楚嗎?
“ x”是對對象的引用; 它不是對象本身。 當你做
x = Thread.CurrentThread.ManagedThreadId.ToString();
您已經丟棄了x先前引用的鎖定對象,並使x引用了其他某個對象。 現在當你做
Monitor.Exit(x);
之所以會發生異常,是因為該對象實際上並未鎖定-您鎖定的對象現在是由垃圾收集器收集的垃圾。
出現這種情況的原因是您要在此處更改x的值:
x = Thread.CurrentThread.ManagedThreadId.ToString();
所以當你去
Monitor.Exit(x)
您正在使用其他對象釋放鎖。 就像您將一個帶鑰匙的掛鎖,然后嘗試從另一個掛鎖中取出帶鑰匙的掛鎖一樣。
此外,與其他控制台相比,Console.Writeline是一條昂貴的指令,因此有多個線程必須先進入Monitor,然后其中一個才能接近終點。
這是一個示例運行:
您啟動了一堆線程。
T1
獲得對象x
的鎖。 T2
嘗試獲取對象x
鎖。 這個線程運氣不好,因為我們知道它將永遠等待。 T1
改變x
。 現在它是一個新對象。 我稱它為x'1
。 T3
嘗試獲取鎖。 但是變量x
實際上引用了對象x'1
。 沒有人鎖定x'1
,所以他通過了。 T3
改變x
。 現在是一個名為x'3
的新對象。 T1
寫入控制台。 T3
寫入控制台。 T1
嘗試使用變量x
釋放鎖定,該變量指向對象... x'3
。 Monitor
對象說:“嘿,您認為您在做什么?您沒有那個鎖!吃這個例外小吸盤”
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.