C lock 關鍵字的一些理解

2022-03-07 07:47:13 字數 3674 閱讀 4067

lock 這個關鍵字,並不是「鎖」,真正的「鎖」是那個被lock的object型別的「物件」,請注意,這裡為「物件」加了雙引號著重強調被lock的是物件型別。

在c# lock關鍵字定義如下:

lock(expression) statement_block  //

其中expression代表你希望跟蹤的物件,通常是物件引用。

根據lock的定義,它有兩種作用

作用1:鎖住括號中的物件

只讓當前執行緒擁有該物件的變數、方法、屬性等的使用權,lock後乙個時刻只可能被乙個執行緒操作。

如果你想保護乙個類的例項,一般地,你可以使用this;如果你想保護乙個靜態變數(如互斥**段在乙個靜態方法內部),一般使用類名就可以了。

作用2:鎖住()後面的**塊(一般放在{}中)

就是定義中的statement_block,這裡代表互斥段的**,這段**在乙個時刻內只可能被乙個執行緒執行。

舉個例子,多數商場廁所的蹲位都是小單間型的,也就是一次只能進去乙個人,商如何確保每次只能進去乙個人呢?不就是乙個人進去之後順手把門鎖上麼?這樣你在裡面幹啥事,外邊的人也只能等待你解放完了,才能進入。以此類推,某個 object 物件被lock之後,lock這個物件的那個執行緒就擁有了執行lock()後面{}的完整的獨立執行權,完整且獨立的執行,不可分割的執行,也就是說,{}是一塊臨界**段。

看下面**

private

static

object objlock = new

object

();lock

(objlock)

根據問題1的答案進行推導,objlock才是那把鎖,lock 一下,當前執行緒就獲得了objlock物件緊跟在lock()後面的{}的獨立使用權,在此期間,其他誰都得等著擁有objlock鑰匙的執行緒執行完之後才能使用{}裡面的**。

更專業一點的說法是:在.net中,每個物件都有乙個與之關聯的鎖,物件可以得到並釋放它以便在任意時間只有乙個執行緒可以訪問物件例項變數和方法。同樣.net中的每乙個物件都可以提供乙個允許自己進入等待狀態的機制。上面提到的獨立使用權,就是物件的互斥鎖。(關於這個說法,求證無果,只是從部落格中找到的,msdn上暫時沒找到相關說法)。

因為只有引用型別才有互斥鎖,如果強行lock值型別,c#會把值裝箱成引用型別,下一次再lock,還會裝箱,這兩次裝箱實際上是裝成了兩個箱子,就不是用乙個記憶體區間了,所以鎖的概念就沒有意義。

還是以廁所為例子吧,私有就好比,這把鎖只有你能訪問到,而且最好這把鎖不會因為外力而有所改變,別人訪問不到,這樣才能保證你進去了,別人就進不去了,如果是公有的,就好比你蹲位小單間的鎖不是安裝在裡面而是安裝在外邊的,別人想不想進就不是你所能控制的了,這樣也不安全。

private

static dictionary _dic=new dictionary();

static

object _obj = new

object

();lock

(_obj)

個人理解上 _dic 存在被其他執行緒修改的可能。

private

static dictionary _dic=new dictionary();

static

object _obj = new

object

();lock

(_obj)

public

void addtodic(int

data)

假設a執行緒執行到lock(_obj)的{}的一半的時候,b執行緒獲取的cpu的使用權,然後b執行緒呼叫了addtodic方法,就會修改_dic的資料。

以上內容為網上蒐集與個人理解,我也不保證一定對。 

private

static

readonly

object obj = new

object();

為什麼要設定成唯讀的呢?這時因為如果在lock**段中改變obj的值,其它執行緒就暢通無阻了,因為互斥鎖的物件變了,object.referenceequals必然返回false。

至於private,上面已經提到了。

lock關鍵字其實就是封裝了moniter類的一些操作,詳情介紹見msdn上關於lock的解釋,下面是原文摘錄。

lock 語句具有以下格式

lock

(x)

其中 x 是引用型別的表示式。 它完全等同於

object __lockobj =x;

bool __lockwastaken = false

;try

finally

關於monitor類這裡暫時不做過多的解釋。

倒是msdn上的乙個示例非常值得借鑑,應該算是lock最簡單的應用方式了。以下示例定義了乙個 account 類,該類通過鎖定專用的 balancelock 例項來同步對其專用 balance 欄位的訪問。 使用相同的例項進行鎖定可確保嘗試同時呼叫 debit 或 credit 方法的兩個執行緒無法同時更新 balance 字段。

using

system;

using

system.threading.tasks;

public

class

account

public

decimal debit(decimal

amount)

");console.writeline($

"amount to remove :");

balance = balance -amount;

console.writeline($

"balance after debit :");

return

amount;

}else}}

public

void credit(decimal

amount)

");console.writeline($

"amount to add :");

balance = balance +amount;

console.writeline($

"balance after credit :");}}

}class

accounttest

task.waitall(tasks);

}static

void

randomlyupdate(account account)

else}}

}

我想著重說明的一些部分:

a、balancelock的用法與命名。balancelock在邏輯上是人為繫結給balance用的「鎖」。

b、考慮這樣乙個問題:如果上面**再加兩個方法直接在不lock balancelock物件的情況下操作balance,那麼這兩個方法在非同步操作的時候,會出現什麼情況??如果乙個帶lock的方法和乙個不帶lock的方法對balance非同步操作又會出現什麼情況??

答案在本文中找。

後記:好多重複,邏輯也有點亂,不打算改了,以上順序就是在思考lock關鍵字的時候就是不斷出現的問題的順序,留作思路。

關於yield關鍵字的一些理解

在ruby中,為什麼有些方法能夠接收引數變數又能接收 塊呢?這是因為啊,這些方法有一種機制來傳輸這些 塊,執行完之後再返回。我們可以在乙個方法中定義這樣一種機制,用yield關鍵字就可以啦。看一下這段 ruby view plain copy print?def block test puts we...

關鍵字 一些關鍵字用法總結

register 用register宣告的變數稱暫存器變數,在可能的情況下會直接存放在機器的暫存器中 但對32位編譯器不起作用,當global optimizations 全域性優化 開的時候,它會做出選擇是否放在自己的暫存器中 不過其它與register關鍵字有關的其它符號都對32位編譯器有效。c...

MySql一些關鍵字

使用distinct關鍵字,只返回不同的值 distinct關鍵字,它必須直接放在列名的前面 eg select distinct id from stu 注意 不能部分使用distinct distinct關鍵字應用於所有列而不僅是前置它的列。如果給出select distinct id,name...