簡體   English   中英

C#鎖定語句,要鎖定的對象是什么?

[英]C# lock statement, what object to lock on?

我有3個需要幫助的問題。

  1. 作為lock語句參數傳遞的正確對象/引用是什么? 我已經看到了許多示例代碼,並且我注意到,只要訪問修飾符static是非公開的,傳入的對象/引用就可能與當前類或程序中的任何其他類無關。 例如:

     private Object anyObj = new Object(); lock(anyObj){.....} private static readonly object Locker = new object(); lock(Locker){.....} 

    這對我來說毫無意義。

  2. 我在MSDN中找到了有關使用lock語句的多線程的示例代碼。 在該示例中,有兩個try / catch塊,其中包含Monitor.Wait() 如果我正確理解邏輯,則readerFlag將完全禁止程序進入try / catch塊。
    該代碼是此處的示例2:
    http://msdn.microsoft.com/zh-CN/library/aa645740(v=vs.71).aspx

  3. 只要Windows窗體處於活動狀態,如何運行在后台運行的線程?

鎖定方式和鎖定方式取決於您在做什么。

假設您正在使用某種設備-例如咖啡壺。 您可能有一個類似於以下內容的類:

public CoffeeMaker {
    private IntPtr _coffeeHandle;
    private Object _lock = new Object();
}

在這種情況下,您將保護對_coffeeHandle的訪問-指向實際物理設備的指針/句柄,因此這非常簡單:

public int AvailableCups {
    get {
        lock (_lock) {
            return GetAvailableCups(_coffeeHandle); // P/Invoked
        }
    }
}

public void Dispense(int nCups)
{
    lock (_lock) {
        int nAvail = GetAvailableCups(_coffeeHandle);
        if (nAvail < nCups) throw new CoffeeException("not enough coffee.");
        Dispense(_coffeeHandle, nCups); // P/Invoked
    }
 }

因此,如果我運行的是多線程應用程序,則(可能)我不想讀取分配時可用的杯子數量(可能是硬件錯誤)。 通過保護對手柄的訪問,我可以確保這一點。 另外,在我已經點膠時也不會要求我點膠-那樣不好,因此也受到保護。 最后,除非我有足夠的咖啡可用,否則我不會分配咖啡,您會注意到我使用我的公共財產進行核實-這樣一來,確保有足夠的咖啡量和分配咖啡量的操作就捆綁在一起了。 不可思議的詞是原子性的-無法將它們切開而不造成問題。

如果您只有一個需要保護的資源實例,則可以使用靜態對象作為鎖。 想一想,“我有一個單身人士嗎?” 這將是您何時需要靜態鎖的指南。 例如,假設CoffeeMaker具有私有構造函數。 相反,您有一個構造咖啡機的工廠方法:

static Object _factLock = new Object();

private CoffeeMaker(IntPtr handle) { _coffeeHandle = handle; }

public static CoffeeMaker GetCoffeeMaker()
{
    lock (_factLock) {
        IntPtr _handle = GetCoffeeMakerHandle(); // P/Invoked
        if (_handle == IntPtr.Zero) return null;
        return new CoffeeMaker(_handle);
    }
 }

現在,在這種情況下,感覺CoffeeMaker應該實現IDisposable以便處理句柄,因為如果不釋放它,則可能有人無法獲得其咖啡。

雖然有一些問題-也許如果咖啡不足,我們應該多做些-這需要很長時間。 哎呀-分配咖啡需要很長時間,這就是為什么我們要謹慎保護資源。 現在您正在考慮,實際上所有這些咖啡壺中的東西都應該在其自己的線程中,並且應該有一個事件在完成咖啡后觸發,然后它開始變得復雜,並且您了解了解的重要性您要鎖定什么以及什么時候鎖定,以免因為您詢問有多少杯而阻止煮咖啡。

如果您對“死鎖”,“原子”,“監視器”,“等待”和“脈沖”一詞聽起來陌生,則應該考慮閱讀多處理/多線程的一般知識,看看是否可以解決公平的理發店問題餐飲哲學家問題 ,都是資源爭奪的典型例子。

1)您的代碼不完整。 您始終鎖定某個(共享)資源。 anyObject與該共享庫的生命周期應具有接近1-1的對應關系。

例如:

a)簡單但最直接的模式:

List<MyClass> sharedList = ...;
...
lock (sharedList) { sharedList.Add(item); }

這種模式有一個缺點:如果其他代碼由於其他原因也鎖定了sharedList怎么辦? 通常這不是一個實際問題,但這是推薦的模式為(b)的原因:

List<MyClass> sharedList = ...;
private object listLock = new object();
...
lock (listLock) { sharedList.Add(item); }

或者,當共享庫為靜態(c)時:

static List<MyClass> sharedList = ...;
private static object listLock = new object();
...
lock (listLock) { sharedList.Add(item); }

2)線程交替將readerFlag設置為true或false,因此將輸入try / catch塊。 同步是通過Monitor.Pulse()和.Wait()完成的。 注意,Wait()將在持續時間s內產生鎖定,沒有死鎖。

1:您使用的對象根據您要強制執行的鎖定粒度進行定義/定義。 如果is是“任何針對當前實例的調用”,則private readonly object syncLock = new object()將是合理的。 如果它是“任何代碼,無論實例如何”(尤其是靜態的),則private readonly static object syncLock = new object() 有時,您嘗試保護的顯而易見的“事物”也將起作用:列表,隊列等。主要的錯誤決策是: thistypeof(...) ,任何string ,任何值類型對每個lock以及您在實例外部泄漏的所有東西進行裝箱。

2: Monitor.Wait從當前線程釋放鎖,等待“脈沖”或超時,這時它將喚醒並加入隊列以重新獲得其擁有的鎖(請注意,存在“ s” -入口)。 這意味着兩個線程可以使用Monitor通過脈沖和等待在它們之間發出信號

3:無關; 但基本上是“定期檢查標記,並在被脈沖時檢查”

根據MSDN文檔

提供給lock關鍵字...的參數用於定義鎖的范圍。 ...嚴格來說,提供的對象僅用於唯一標識多個線程之間共享的資源,因此它可以是任意的類實例。 但是,實際上,該對象通常表示需要進行線程同步的資源。

就我而言,我已經傳遞了需要更改的確切靜態對象。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM