2011-01-08 101 views
4
// Member Variable 
private static readonly object _syncLock = new object(); 

// Now inside a static method 

foreach (var lazyObject in plugins) 
{ 
    if ((string)lazyObject.Metadata["key"] = "something") 
    { 
     lock (_syncLock) 
     { 
     // It seems the `IsValueCreated` is not up-to-date 
     if (!lazyObject.IsValueCreated) 
      lazyObject.value.DoSomething(); 
     } 
     return lazyObject.value; 
    } 
} 

這裏我需要每個循環的同步訪問。有很多線程迭代這個循環,並且基於他們正在尋找的key,創建並返回一個懶惰的實例。使用MEF的線程安全惰性實例化

lazyObject不應該創建更多的一次。雖然Lazy類是這樣做的,儘管使用了鎖,但在高線程下,我創建了不止一個實例(我通過volatilestatic int上的Interlocked.Increment進行跟蹤並將其記錄在某處)。問題是我沒有訪問Lazy的定義,而MEF定義Lazy類如何創建對象。我應該注意到CompositionContainer在已經使用的構造函數中有一個線程安全選項。

我的問題:

1)爲什麼鎖不起作用?

2)我應該使用一組鎖而不是一個鎖來提高性能嗎?

+0

自己是不是在該代碼(這使得它很難看你有沒有這個問題)完全正確。你有一個靜態成員函數訪問類的非靜態成員變量(它不會編譯) – 2011-01-08 12:09:46

+0

當然這是靜態的。編輯。 – Xaqron 2011-01-08 12:25:00

+0

嘗試將`return lazyObject.value`移動到鎖內。 – jgauffin 2011-01-08 13:40:30

回答

4

您的Lazy複合體中的默認構造函數是T? MEF使用LazyThreadSafetyMode.PublicationOnly這意味着訪問單元化Lazy的每個線程將在T上生成new(),直到第一個完成初始化。然後對當前訪問.Value的所有線程返回該值,並丟棄它們自己的new()實例。如果你的構造函數很複雜(也許做得太多了),你應該將它重新定義爲做最少的構建工作並將配置移動到另一種方法。

您需要考慮整個方法。如果你考慮:

public IPlugin GetPlugin(string key) 
{ 
    mutex.WaitOne(); 

    try 
    { 
    var plugin = plugins 
     .Where(l => l.Metadata["key"] == key) 
     .Select(l => l.Value); 
     .FirstOrDefault(); 

    return plugin; 
    } 
    finally 
    { 
    mutex.ReleaseMutex(); 
    } 
} 

您還需要考慮到,如果plugins是不是隻讀的,那麼你需要同步訪問該實例太多,否則很可能在另一個線程上進行修改,從而導致你的代碼翻倒。

0

還有就是Lazy<T, TMetadata>對於這樣的場景,在這裏你定義一個LazyThreadSafetyMode構建一個懶惰的實例時......否則,鎖可能不適用於許多不同的原因,如工作的特定構造如果這不是Lazy<T>實例的Value屬性曾被訪問過的唯一地方。

順便說一句,你有我錯字在if聲明...