2014-05-19 2 views
4

은 이제 나는이 간단한 코드 있다고 가정 해 봅시다 : (단순화)ConcurrentDictionary 및 atomic 연산 - 때때로 잠금이 필요합니까?

MyConCurrentDictionary는 (다른 클래스에 존재하는) 정적 ConcurrentDictionary<string, string>입니다

.

/*1*/ public void Send(string Message, string UserName) 
/*2*/ {    
/*3*/  string ConnectionId; 
/*4*/  if (MyConCurrentDictionary.TryGetValue(UserName,out ConnectionId)) 
/*5*/  { 
/*6*/  //... 
/*7*/   DB.InsertMessage(Message, ConnectionId); 
/*8*/   LOG.LogMessage (Message, ConnectionId); 
/*9*/  //... 
/*10*/  } 
/*11*/  else ... 
/*12*/ } 

이 방법은 많은 경우 실행됩니다. (signalR 허브, 당신이 할 경우)

나는 user/connectionID이있는 경우 DB/log에 삽입해야합니다.

그렇게 OK 선 #4 인 스레드 멀티 스레드가 ConcurrentDictionary

액세스되지만 RemoveUser 또 다른 방법이있을 때 안전 - 사전에서 사용자를 제거 :

public void RemoveUser (string userName) 
     { 
      string removed; 
      if (MyConCurrentDictionary.TryRemove(userName,out removed)) 
       Clients.All.removeClientfromChat(userName); 
     } 

는하지만 그것이 가능한 문맥 #5 줄에서 발생합니다. RemoveUser을 제거합니다. ConcurrentDictionary에서 UserName을 제거하십시오.

lock(locker) 
{ 
    if (MyConCurrentDictionary.TryGetValue(UserName,out ConnectionId)) 
    { 
    //... 
    } 

} 

완전히 패배ConcurrentDictionary의 목적 : -

그래서이 문제를 해결하기 위해 코드는 다음과 같은 것이다.

질문

동안 다중 스레드 환경에서 같은 일을하고 오른쪽 방법은 무엇입니까 - 여전히 ConcurrentDictionary의 이익을 가지고가?

nb, 예 ConcurrentDictionary는 사전 내에서만 작동하는 스레드 안전입니다. 하지만 내가 말하고자하는 것은 특정 시나리오에서 ConcurrentDictionary의 이점을 잃어버린다는 것입니다. 여전히 잠금을 사용해야하기 때문입니다.

+0

"ConcurrentDictionary에서 UserName을 제거하십시오."# 5에서 그런 코드가 보이지 않습니다. – Magnus

+0

더 많은 코드를 보여주십시오. 어디에서 제거합니까? 'ConcurrentDictionary'는 thread safe 한'TryRemove' 메소드만을 가지고 있습니다. 그래서 그것이 당신의 문제가되어서는 안됩니다. 너의 문제는 무엇인가? –

+0

@SriramSakthivel 공용 작업이 스레드 안전하다는 것을 알고 있습니다. 하지만 여전히 모든 것이 여전히 괜찮을 수 있지만, 다른 스레드는 라인 # 5 퀀텀에 들어가서 제거 할 수 있습니다 (사용자가 로그 아웃하기 때문에). 그래서 여기에 분무기가 필요합니다. –

답변

2

작성한 내용과 지금까지 내가 이해 한 내용을 바탕으로 ConcurrentDictionary가 적절한 선택이 아닙니다!

일반 사전을 래핑하고 읽기 및 쓰기 작업을 ReaderWriterLockSlim으로 캡슐화하는 클래스를 작성합니다. 이것은 일반 잠금 장치보다 훨씬 빠릅니다. 또한 한 번에 여러 번 읽을 수 있지만 한 번만 기록 할 수 있습니다.

private ReaderWriterLockSlim _lock = new ReaderWriterLockSlim(); 

public void DoRead(string xyz) 
{ 
    try 
    { 
     _lock.EnterReadLock(); 
     // whatever 
    } 
    finally 
    { 
     _lock.ExitReadLock(); 
    } 
} 

public void DoWrite(string xyz) 
{ 
    try 
    { 
     _lock.EnterWriteLock(); 
     // whatever 
    } 
    finally 
    { 
     _lock.ExitWriteLock(); 
    } 
} 
1

디자인 문제가있는 것 같습니다.

당신은 ConcurentDictionary이지만 원자 적으로 사용하지 마십시오. lock (또는 다른 동기화)을 사용해야하므로 몇 가지 명령으로 구성된 작업이 있습니다.

간단한 솔루션은 LOG 메시지를 처리 ​​할 때마다 이미 과정을, 즉,이 CAS (MyConcurentDictionary에서 TryGetValue를 사용)를 사용자 ID를 삭제 LOG로 메시지를 가질 수 있도록하는 것입니다. 나는 또한이 명 컬렉션을 문제에 대해 생각할 수있는

: 당신이 유효 등이다 사용자 ID를 하나, 당신이 사용자을 삭제했다. LOG에 추가하려면 콜렉션이 확인됩니다.사용자를 삭제하려면 해당 사용자를 에 삭제 된 사용자 컬렉션에 추가하고 시간 후에 유효 기간 (해당 시간 = 1 초 또는 그 이상)에서 해당 사용자를 삭제하십시오.

+0

이 샘플은 단순화 된 것입니다. 더 이상 관련이 없다면 일어날 수없는 일들이 있습니다. 나는 자물쇠가 어떻게 여기에서 사용될 수 있는지에 관해 안다. –

+0

* 잠금 장치가 여기에 어떻게 사용되는지는 알지 못합니다 *, 그 이유는 대답을 썼습니다. 그것으로부터 어느 쪽의 해결책이라도 사용할 수 있습니까? – Sinatr

관련 문제