2012-07-23 2 views
7

이 코드에 대해 다음과 같은 가정이 유효합니까? 코드 밑에 배경 정보를 넣었지만 관련성이 있다고는 생각하지 않습니다.ASP.NET의 런타임에 동적 잠금 만들기

가정 1 : 이것은 단일 응용 프로그램이므로 하나의 프로세스에서 처리 할 것이라고 가정합니다. 따라서 정적 변수는 스레드간에 공유되며 잠금 개체의 정적 컬렉션을 정적으로 선언하는 것이 유효합니다.

가정 2 : 값이 이미 사전에 있다는 것을 알고 있으면 읽기를 잠글 필요가 없습니다. ConcurrentDictionary를 사용할 수는 있지만 열거 형 (또는 삭제 중)이 아니기 때문에 안전하다고 믿습니다. UnlockOnValue()을 호출하면 값이 존재하고 변경되지 않습니다.

가정 3 : 기본 데이터 구조의 경우에도 참조가 변경되지 않으므로 키 컬렉션을 잠글 수 있습니다.

private static Dictionary<String,Object> LockList = 
    new Dictionary<string,object>(); 

private void LockOnValue(String queryStringValue) 
{ 
    lock(LockList.Keys) 
    { 
     if(!LockList.Keys.Contains(queryStringValue)) 
     { 
      LockList.Add(screenName,new Object()); 
     } 
     System.Threading.Monitor.Enter(LockList[queryStringValue]); 
    } 
} 

private void UnlockOnValue(String queryStringValue) 
{ 
    System.Threading.Monitor.Exit(LockList[queryStringValue]); 
} 

그런 다음 내가 좋아하는이 코드를 사용합니다 :

LockOnValue(Request.QueryString["foo"]) 
//Check cache expiry 
//if expired 
    //Load new values and cache them. 
//else 
    //Load cached values 
UnlockOnValue(Request.QueryString["foo"]) 

배경 : 나는 다운로드 데이터를 쿼리에서 단일 사용자 정의 변수를 기반으로한다는 ASP.NET에서 응용 프로그램을 만드는거야 끈. 값의 수는 매우 제한됩니다. 지정된 기간 동안 각 값에 대한 결과를 캐시해야합니다.

접근 방식 : 로컬 파일을 사용하여 캐시하는 것이 가장 좋은 방법은 아니지만 중요한 사항은 아니며 성능이 큰 문제가 아니기 때문에 시도해 보았습니다. 나는 옵션 당 2 개의 파일을 사용했다. 하나는 캐시 만료일이고 다른 하나는 데이터이다.

문제점 : 잠금을 수행하는 가장 좋은 방법은 무엇인지 모르겠으며 .NET에서 스레드 문제에 지나치게 익숙하지 않습니다. (이 방법을 선택한 이유 중 하나). 사용할 수있는 내용과 읽은 내용을 바탕으로 위의 내용이 제대로 작동 할 것이라고 생각했지만 확신이 없으며 다른 의견을 원했습니다.

+1

'HttpRuntime.Cache'를 사용할 때의 문제점은 무엇입니까? – scottm

+0

그건 내 첫 번째 선택 이었지만 이상하게 행동했습니다. 그것은 내 페이지가 응답을 지우고 텍스트 파일을 반환하기 때문일 수 있습니다. 그러나 비슷한 문제로 뛰어 들었을 때 모든 인터넷에 게시 된 답변이 없기 때문에 너무 심하게 발굴하지 않았습니다. IIS 구성과 캐싱이 올바르게 구성되었는지 여부는 내가 들어 본 것이 아닙니다. 나중에도 그렇게 할 수는 있지만 중요하지 않은 코드이므로 궁극적 인 아키텍처가 아니더라도 답변을 원했던 질문이 제기되었습니다. – Kendrick

+0

나는 메소드 결과를 캐싱하는 것과 비슷한 솔루션을 구현하려고합니다. 또한 다른 캐시 잠금을 만드는 방법이 필요하며 솔루션이 시간의 테스트를 참아 냈는지 궁금합니다. –

답변

6

현재 솔루션이 상당히 좋아 보입니다. 내가 바꿀 두 가지 :

1 : UnlockOnValue는 finally 블록에 있어야합니다. 예외가 슬로우되면 잠금을 해제하지 않습니다.

2 : LockOnValue는 사전 조회를 두 번 수행하므로 다소 비효율적입니다.작은 사전에는 큰 문제가 아니지만 큰 사전에는 TryGetValue로 전환해야합니다.

또한 가정 3은 현재 보유하고 있습니다. 그러나 Dictionary 계약은 Keys 속성이 항상 동일한 객체를 반환한다고 보장하지 않습니다. 그리고 이것에 의존하지 않는 것이 쉽기 때문에 나는 그것에 대해 추천 할 것입니다. 잠글 개체가 필요할 때마다 그 목적을 위해 개체를 만듭니다. 다음과 같은 것 :

private static Object _lock = new Object(); 
+0

의사 코드에서 지정해야하지만 finally 블록에 있습니다. 나는 TryGetValue에 대해 생각해 본 적이 없지만 아마도 더 나은 선택 일 것이다. 사전은 작지만 여전히 생각하기 좋다. – Kendrick

+0

예, 그것은 Contains에 대한 호출을보고 나서 []에 대한 호출을 볼 수있는 애완 동물입니다. 왜냐하면 둘 다 요소를 찾아야하기 때문입니다. – bmm6o

1

lock에는 단일 프로세스의 범위 만 있습니다. 프로세스를 확장하려면 Mutex (명명 된)과 같은 프리미티브를 사용해야합니다.

lockMonitor.EnterMonitor.Exit과 동일합니다. Monitor.EnterMonitor.Exit도 수행하면 중복됩니다.

읽기를 잠글 필요는 없지만 값이 존재하지 않는지 확인한 후 트랜잭션을 잠 가서 추가해야합니다. 일련의 지침을 잠그지 않으면 키를 확인할 때 키를 추가 할 때와 추가 할 때 사이에 다른 것이 생길 수 있으므로 예외가 발생합니다. 당신이하고있는 자물쇠는 그것을하기에 충분합니다 (당신은 Enter와 Exit에 대한 추가 호출이 필요 없습니다 - 자물쇠는 당신을 위해 그것을 할 것입니다).

+0

이 응용 프로그램의 모든 스레드가 동일한 프로세스에서 생성 될 것으로 가정합니다. 내가 100 % 확실하지는 않지만 필자가 그 모든 것을 지적한 문서와 예제가 그 것이다. 정말로 제가 정말로 확신하지 못하는 두 번째 가정입니다. 첫 번째는 정확하고 세 번째는 맞을 것이라고 생각합니다. 그러나 사전에 대한 잠금 객체를 만드는 것 이상의 일을 할 이유가 없습니다. (즉, 작동 할 수도 있지만 나쁜 코드 일 수도 있습니다) – Kendrick

+0

하나의 응용 프로그램이고 모든 스레드가 프로세스의 단일 인스턴스에서 잠금은 해당 상황에 맞습니다. –