2012-11-29 6 views
1

나는 다음과 같은 코드가 있습니다이 특정 유형의 잠금을 수행하는 방법은 무엇입니까?

var sequence = from row in CicApplication.DistributorBackpressure44Cache 
        where row.Coater == this.Coater && row.IsDistributorInUse 
        select new GenericValue 
        { 
         ReadTime = row.CoaterTime.Value, 
         Value = row.BackpressureLeft 
        }; 

    this.EvaluateBackpressure(sequence, "BackpressureLeftTarget"); 

다음과 같이 DistributorBackpressure44Cache 정의됩니다 :

internal static List<DistributorBackpressure44> DistributorBackpressure44Cache 
{ 
    get 
    { 
     return _distributorBackpressure44; 
    } 
} 

이 DistributorBackpressure44Cache은 하나 개의 스레드에서 갱신, 그리고에서 조회되는 수 무겁게 스레드 응용 프로그램의 일부입니다 위에 표시된 것처럼 다른 스레드에서. 위의 변수 'sequence'는 IEnumerable이며 표시된 메서드에 전달 된 다음 실제로 실행되기 전에 다른 메서드로 전달 될 수 있습니다. 제 관심은 이것입니다. 쿼리가 실제로 실행될 때 DistributorBackpressure44Cache가 새로 고쳐지거나 (지워지고 다시 채워지는) 위의 쿼리는 어떻게됩니까?

이 코드가 실제로 어떤 시점에서 나중에 실행되기 때문에이 코드 주위에 잠금을 설정하는 것은 좋지 않습니다 (목록으로 즉시 변환하지 않는 한).

답변

1

디자인에서 허용 할 수있는 경우이 코드로 스냅 샷 수준 격리를 보장하고 모두 잠그지 않아도됩니다. 그러나, 당신은 다음을 수행해야합니다 :

  1. 만들기 대신 ReadOnlyCollection<T>을 반환 DistributorBackpressure44Cache,이 방법은이 데이터를 변이 안 명시 적입니다.

  2. 복사시 _distributorBackpressure44의 돌연변이가 발생하고 원자 단위 할당이 완료되면 _distributorBackpressure44으로 되 돌아 가게하십시오.

    var cache = _distributorBackpressure44.ToList(); 
    this.RefreshCache(cache); // this assumes you *need* to know 
              // about the structure of the old list 
              // a design where this is not required 
              // is preferred 
    
    _distributorBackpressure44 = cache; // some readers will have "old" 
                // views of the cache, but all readers 
                // from some time T (where T < Twrite) 
                // will use the same "snapshot" 
    
0

아키텍처 옵션에 대해 알지 못하면 다음과 같이 할 수 있습니다.

lock(CicApplication.DistributorBackpressure44Cache) 
{ 
    var sequence = from row in CicApplication.DistributorBackpressure44Cache 
        where row.Coater == this.Coater && row.IsDistributorInUse 
        select new GenericValue 
        { 
         ReadTime = row.CoaterTime.Value, 
         Value = row.BackpressureLeft 
        }; 
} 

this.EvaluateBackpressure(sequence, "BackpressureLeftTarget"); 

그런 다음 코드를 수정/새로 고침하면 다음과 같이됩니다.

lock(CicApplication.DistributorBackpressure44Cache) 
{ 
    var objCache = CicApplication.DistributorBackpressure44Cache 

    objCache.Clear(); 

    // code to add back items here 
    // [...] 
} 

캐시를 둘러싼 모든 것을 제어하는 ​​중앙 클래스 (싱글 톤 패턴일까요?)가 있으면 더 깨끗합니다. 그러나 이것이 가능한지 (즉, 쿼리 코드를 다른 클래스에 넣고 매개 변수를 전달하는 것) 어떻게 할 수 있는지 모르겠습니다. 더 멋진 기술 대신에, 위의 솔루션은이 객체를 읽고 쓸 때마다 매번 lock()하는 것을 기억하는 한 계속 작동해야합니다.

+0

는 사실은 이미 두 번째 부분을하고 있어요.그러나 쿼리를 즉시 실행하는 쿼리에 .ToList()를 추가하지 않으면 쿼리가 실제로 나중에 어떤 시점 (즉, Linq 작동 방식)에서 실행되기 때문에 쿼리를 둘러싼 잠금을 설정하면 어떤 이점이 있습니까? . –

+0

그러면 lock()에서 LINQ의 실제 평가 (즉, for 루프)를 둘러 쌀 수 있습니다. –

+1

특히 Nreaders >> Nwriters 인 경우 판독기 - 기록기 잠금이 모니터 잠금보다 우수합니다. – user7116

1

당신은

또는

당신은에 잠금을 넣을 수 있습니다 (best-- 수 있습니다) 즉시 목록에 변환 할 수 DistributorBackpressure44 얻을 것을 캐시 새로 고침 잠금 한단. 잠금 및 잠금 해제 된 접근자를 포함 할 수 있습니다. 결과가 즉시 사용되면 잠금 해제 된 접근자를 사용하고 지연된 실행 상황에서 접근자를 사용할 때 잠긴 접근자를 사용합니다.

캐시 새로 고침이 _distributorBackpress44 목록을 변경하면 참조 된 목록을 바꾼 경우에만 작동합니다.

+0

캐시 새로 고침 코드는 목록을 지운 다음 다시 채 웁니다. 새 목록 개체가 생성되지 않습니다. –

관련 문제