2013-12-22 1 views
0

ConcurrentDictionary 키와 관련된 값을 바꾸면 해당 키를 넘어서는 사전 작업이 잠 깁니 까?다른 ConcurrentDictionary 키의 작업을 대체하면 하나의 잠금이 공유됩니까?

편집 :

public static class Test { 
    private static ConcurrentDictionary<int, int> cd = new ConcurrentDictionary<int, int>(); 
    public static Test() { 
     new Thread(UpdateItem1).Start(); 
     new Thread(UpdateItem2).Start(); 
    } 
    private static void UpdateItem1() { 
     while (true) cd[1] = 0; 
    } 
    private static void UpdateItem2() { 
     while (true) cd[2] = 0; 
    } 
} 

처음에 내가 가정 : 키가 먼저 다음에 추가 될 때 예를 들어은 나도 thread가 외에, 다른 차단합니다 있는지 알고 싶습니다 예를 들어, dictionary[key] = value;이 아직 존재하지 않는 키를 참조 할 수 있기 때문입니다. 그러나 작업하는 동안 추가가 필요한 경우 별도의 잠금 에스컬레이션 후에 발생할 수 있음을 알았습니다.

다음 클래스를 초안을 작성했지만이 질문에 대한 대답이 "아니오"인 경우 AccountCacheLock 클래스에서 제공하는 간접 지정은 필요하지 않습니다. 사실, 내 자신의 모든 자물쇠 관리는 거의 불필요합니다.

// A flattened subset of repository user values that are referenced for every member page access 
public class AccountCache { 

    // The AccountCacheLock wrapper allows the AccountCache item to be updated in a locally-confined account-specific lock. 
    // Otherwise, one of the following would be necessary: 
    // Replace a ConcurrentDictionary item, requiring a lock on the ConcurrentDictionary object (unless the ConcurrentDictionary internally implements similar indirection) 
    // Update the contents of the AccountCache item, requiring either a copy to be returned or the lock to wrap the caller's use of it. 
    private static readonly ConcurrentDictionary<int, AccountCacheLock> dictionary = new ConcurrentDictionary<int, AccountCacheLock>(); 

    public static AccountCache Get(int accountId, SiteEntities refreshSource) { 
     AccountCacheLock accountCacheLock = dictionary.GetOrAdd(accountId, k => new AccountCacheLock()); 
     AccountCache accountCache; 
     lock (accountCacheLock) { 
      accountCache = accountCacheLock.AccountCache; 
     } 
     if (accountCache == null || accountCache.ExpiresOn < DateTime.UtcNow) { 
      accountCache = new AccountCache(refreshSource.Accounts.Single(a => a.Id == accountId)); 
      lock (accountCacheLock) { 
       accountCacheLock.AccountCache = accountCache; 
      } 
     } 
     return accountCache; 
    } 

    public static void Invalidate(int accountId) { 
     // TODO 
    } 

    private AccountCache(Account account) { 
     ExpiresOn = DateTime.UtcNow.AddHours(1); 
     Status = account.Status; 
     CommunityRole = account.CommunityRole; 
     Email = account.Email; 
    } 

    public readonly DateTime ExpiresOn; 
    public readonly AccountStates Status; 
    public readonly CommunityRoles CommunityRole; 
    public readonly string Email; 

    private class AccountCacheLock { 
     public AccountCache AccountCache; 
    } 
} 

사이드 질문 : 이미 ASP.NET 프레임 워크에 뭔가가 있습니까?

+0

정확한 잠금은 무엇에 의존하고 있습니까? 나는 당신이 아직 성취하려는 것을 이해하지 못했습니다 ... –

+0

Hey Jon. 나는 귀하의 명확한 요구를 이해하고 있는지 확신 할 수 없습니다. 나는 그것이 단어가 빠진 것이 틀림 없다고 확신하지만, 나는 어떤 것을 알아낼 수 없다. 내가 다시 말하려고합니다 : 다른 항목의 추가를 차단하거나 다른 키 값의 읽기 또는 바꾸기를 차단하지 않고 사전의 항목을 바꾸려고합니다. 위의 독점 코드에서'AccountCacheLock'으로 추가 한 추가 잠금 레이어가 필요합니까? 아니면 간단히'ConcurrentDictionary [key] ='를 호출 할 수 있습니까? – shannon

+0

궁극적으로, 나는 자주 사용되는 계정 (및 하위) 정보에 대한 캐시를 계정 ID에 입력하기 만하려고합니다.나는 단순히 항목을 대체하기 위해 동시 사전을 요청하면 교체 기간 동안 모든 스레드가 캐시를 사용하지 못하도록 차단할 것입니다. – shannon

답변

2

자물쇠를 할 필요가 없습니다. ConcurrentDictionary가이를 잘 처리해야합니다.

사이드 질문 : 이미 ASP.NET 프레임 워크에 뭔가가 있습니까?

물론. ASP.NET과 관련이있는 것은 아니지만 System.Runtime.Caching 네임 스페이스, 특히 MemoryCache 클래스를 살펴볼 수 있습니다. 스레드 안전 해시 테이블의 맨 위에 만료 및 콜백과 같은 항목을 추가합니다.

업데이트 된 답변에 표시된 AccountCache의 목적을 이해하지 못합니다. 그것은 단순한 캐싱 레이어가 당신에게 무료로 제공하는 것입니다.

웹 팜에서 ASP.NET 응용 프로그램을 실행하려는 경우 분명히 예를 들어 memcached와 같은 일부 분산 캐싱을 고려해야합니다. memcached 프로토콜 위에 ObjectCache 클래스의 .NET 구현이 있습니다.

+0

내 질문에 'AccountClass'을 찾을 수 없습니다. 'AccountCache'를 의미 할 수도 있습니다. 그렇다면 Account 개체뿐 아니라 몇 가지 관련 개체 및 보안 규칙에서 축소 된 일부 관련 정보를 보유하기위한 것입니다. 또한 자주 사용되는 Account 속성이 거의 없을 때 전체 계정 개체 캐싱을 방지하기위한 것입니다. 불필요한 속성 (특히 전체 계층 구조)을 캐싱하면 메모리 오버 헤드가 증가 할뿐만 아니라 단순 캐시 구현에서 항목이 무효화되는 빈도가 증가합니다. 이해 했니? – shannon

+0

예, 확실히 MemoryCache 클래스에있는 기능을 완전히 복제 할 가능성이 있습니다. 나는 그것에 대해 논쟁하지 않는다. 조사 할께. – shannon

+1

죄송합니다. 나는 'AccountCache'를 의미했다. 전체 Account 객체가 너무 커서 캐시 될 수없는 경우 MemoryCache로 캐시 될 일부 뷰 (뷰 모델)를 사용해보십시오. IMHO 캐싱은 어렵습니다. 고유 한 롤을 시도하는 대신 프레임 워크에 내장 된 클래스를 사용하는 것이 좋습니다. –

0

또한 ConcurrentDictionary 내부에서 피싱을 들었을뿐만 아니라 개별 항목이나 전체 사전에는 항목 대체가 잠기지 않고 항목의 해시 (예 : 항목과 연관된 잠금 개체)가 잠긴 것처럼 보입니다. 사전 "버킷"). 사전의 크기를 조정할 필요가 없다면 키의 초기 소개가 전체 사전을 잠그지 않도록 설계된 것 같습니다. 이것은 일치하는 해시를 생성하지 않는다면 두 개의 업데이트가 동시에 발생할 수 있음을 의미합니다.

관련 문제