2014-10-21 2 views
1

I했습니다 빼 안전 수집 목록을 사용하는 등 기능, 또한 잠금 연산자 사용 스레드 안전을 위해 : 나는 그것을 할로 변환 할사용하여 스레드 안전 ConcurrentDictionary 수집

public void ShowData(ref DataGridView dmRequests, ref DataGridView URL, ref DataGridView dmData, ref DataGridView errorCodes) 
{ 
    List<KeyValuePair<string, ulong>> dmReqList = new List<KeyValuePair<string, ulong>>(); 
    List<KeyValuePair<string, ulong>> urlReqList = new List<KeyValuePair<string, ulong>>(); 
    List<KeyValuePair<string, ulong>> dmDataList = new List<KeyValuePair<string, ulong>>(); 
    List<KeyValuePair<string, ulong>> errCodesList = new List<KeyValuePair<string, ulong>>(); 

    lock (m_logStruct.domainName) 
    { 
     dmReqList = m_logStruct.domainName.ToList(); 
    } 
    lock(m_logStruct.URL) 
    { 
     urlReqList = m_logStruct.URL.ToList(); 
    } 
    lock(m_logStruct.domainData) 
    { 
     dmDataList = m_logStruct.domainData.ToList(); 
    } 
    lock(m_logStruct.errorCodes) 
    { 
     errCodesList = m_logStruct.errorCodes.ToList(); 
    } 

    dmRequests.DataSource = dmReqList.OrderBy(x => x.Key).ToList(); 
    URL.DataSource = urlReqList.OrderBy(x => x.Key).ToList(); 
    dmData.DataSource = dmDataList.OrderBy(x => x.Key).ToList(); 
    errorCodes.DataSource = errCodesList.OrderBy(x => x.Key).ToList(); 
} 

을 자물쇠가 없다. 그것을 위해 내 기능이 너무보고 시작, 그래서 대신 목록 모음의 기능 ConcurrentDictionary 수집에 사용했습니다

public void ShowData(ref DataGridView dmRequests, ref DataGridView URL, ref DataGridView dmData, ref DataGridView errorCodes) 
{ 
    try 
    { 
     ConcurrentDictionary<string, ulong> dmReqList = new ConcurrentDictionary<string, ulong>(); 
     ConcurrentDictionary<string, ulong> urlReqList = new ConcurrentDictionary<string, ulong>(); 
     ConcurrentDictionary<string, ulong> dmDataList = new ConcurrentDictionary<string, ulong>(); 
     ConcurrentDictionary<string, ulong> errCodesList = new ConcurrentDictionary<string, ulong>(); 

     dmReqList = m_logStruct.domainName; 
     urlReqList = m_logStruct.URL; 
     dmDataList = m_logStruct.domainData; 
     errCodesList = m_logStruct.errorCodes; 

     dmRequests.DataSource = dmReqList.OrderBy(x => x.Key); 
     URL.DataSource = urlReqList.OrderBy(x => x.Key).ToList();//I get error here: Index is out of range     
     dmData.DataSource = dmDataList.OrderBy(x => x.Key).ToList();    
     errorCodes.DataSource = errCodesList.OrderBy(x => x.Key).ToList(); 
    } 
    catch(IOException e) 
    { 
     MessageBox.Show(e + " Something bad has been occurred here!"); 
    } 

} 

을하지만 시작이 기능에 (인덱스가 범위를 벗어나) 오류가 발생합니다. 스레드 안전 컬렉션 (ConcurrentDictionary) 올바르게 사용하는 방법? 내 오류를 해결하는 방법?

+0

새 사전을 선언했지만 immedatly 덮어 씁니다. 당신은 당신의 모든 새로운 ConcurrentDictionary ();'을 제거 할 수 있습니다, 그들은 당신을 위해 아무것도하지 않습니다. –

+0

샘플은 여러 스레드 (모든 로컬 변수)에 변수를 노출 할 수없는 코드를 보여줍니다. 코드를 업데이트하여 다중 스레드에서'errCodesList '와 같은 것을 실제로 보여줄 수 있습니다. –

+2

사이드 노트 : 샘플을 하나의 콜렉션 세트로 줄이는 것을 고려하십시오. 각 기능에 거의 동일한 4 개의 섹션이 추가 정보를 제공하지는 않습니다. –

답변

1

목록을 저장할 변수를 바꾸는 경우 병행하지 않을 것입니다. 제공하는 동시 메소드를 사용해야합니다. MSDN article의 예를 참조하십시오.

사용 TryAdd, TryUpdate, TryRemove 또는 AddOrUpdate 목록에 추가하거나 업데이트 목록을 너무보다는하기 위해 :

dmReqList = m_logStruct.domainName; 

수행 뭔가 같은 :

foreach (var item in m_logStruct.domainName) 
{ 
    dmReqList.TryAdd(item.Key, item.Value); 
} 

UPDATE :로 Alexei가 지적했듯이 dmReqList를 로컬에서 정의하고 있습니다. 이것은 ConcurrentDictionary라는 이점을 얻지 못한다는 것을 의미합니다. 다른 스레드가 어쨌든 액세스 할 수 없기 때문입니다. 또한 원래 예제에서 m_logStruct에 잠금을 적용했기 때문에 다른 스레드를 통해 액세스 할 수 있다는 것을 암시합니다. 암시가 맞으면 ConcurrentDictionary가되어야합니다. 따라서 코드가 다음과 같이 표시되어야합니다.

private ConcurrentDictionary<string, ulong> _domainNames = new ConcurrentDictionary<string, ulong>(); 

public void ShowData(ref DataGridView dmRequests) 
{ 
    dmRequests.DataSource = _domainNames.OrderBy(x => x.Key); //Set the current values of the dictionary to the grid. 
} 

public void MultiThreadedMethod() 
{ 
    _domainNames.TryAdd(someKey, someValue); //Access the dictionary from multiple threads. 
} 
+0

'ConcurrentDictionary'를 사용하는 방법에 대한 질문에 다소 답하는 동안,이 제안은 다중 쓰레드로부터'm_logStruct'에 접근 할 수 있기 때문에 쓰레드에 안전하지 않습니다. 다른 스레드에서 볼 수없는 지역 변수에'ConcurrentDictionary'를 사용하면 일반 목록/사전에 비해 더 이상 "스레드 안전성"이 보장되지 않습니다. –

+0

OP는 m_logStruct에 대한 정의를 제공하지 않았지만 관례에 따라이 변수는 개인 전역 변수라고 가정 할 수 있습니다. 사실, m_logStruct가 다중 쓰레드에 접근 할 수 있다면 그것을 변경하는 것은 "아마도 스레드 안전성이 충분하지 않을 수 있습니다"하지만 OP는 m_logStruct에 대한 액세스가 아니라 dmReqList에 대한 액세스를 걱정하지 않으므로 OP가 이미 알고 있다고 가정해야합니다. 또한 dmReqList는 로컬 변수가 아닙니다. OP의 메소드 정의를 살펴보면, 참조로 메소드에 정의를 전달합니다. –

+0

"dmReqList가 로컬 변수가 아닙니다."- 그게 뭐야? 원래의 코드는'lock (m_logStruct.domainName)'에 잠금을 걸었 기 때문에'm_logStruct'처럼 보이고 그 필드는 보호가 필요합니다. (제공된 샘플 샘플은 다소 임의의 코드입니다. 즉, ref로 모든 매개 변수를 전달하거나 별도의 객체 - 그래서 * OP가 특정 코드에 대해별로 신경 쓰지 않고 단지'ConcurrentDictionary' 사용에 대한 팁에 관심이 있음을 의미 할 수도 있습니다. –