2010-08-23 4 views
6

다음 코드에서 .NET 4의 ConcurrentDictionary 및 ConcurrentQueue 클래스를 사용하고 있습니다.ConcurrentDictionary와 ConcurrentQueue의이 조합은 스레드로부터 안전한가요?

이 코드는 스레드로부터 안전한가요? 그렇지 않다면 어떻게 스레드로부터 안전하게 만들 수 있습니까?

public class Page 
{ 
    public string Name {get; set; } 
} 

public class PageQueue 
{ 
    private ConcurrentDictionary<int, ConcurrentQueue<Page>> pages = 
     new ConcurrentDictionary<int, ConcurrentQueue<Page>>(); 

    public void Add(int id, Page page) 
    { 
     if (!this.pages.ContainsKey(id)) 
      this.pages[id] = new ConcurrentQueue<Page>(); 

     this.pages[id].Enqueue(page); 
    } 

    public Page GetAndRemove(int id) 
    { 
     Page lp = null; 

     if(this.pages.ContainsKey(id)) 
      this.pages[id].TryDequeue(out lp); 

     return lp; 
    } 
} 

데모 :

public class Demo 
{ 
    public void RunAll() 
    { 
     for (int i = 0; i < 10; i++) 
      Task.Factory.StartNew(() => Run()); 
    } 

    public void Run() 
    { 
     PageQueue pq = new PageQueue(); 
     pq.Add(1, new Page()); 

     pq.GetAndRemove(1); 
    } 
} 

답변

10

, 코드에서 일부 결함이있다. 나는 당신이 lock 문에 대한 필요없이 코드가 스레드 안전 할 ConcurrentDictionary<K,V>에서 제공하는 많은 방법을 활용 제안 : 당신이 ** **`lock`를 사용하지 않아도

public class PageQueue 
{ 
    private ConcurrentDictionary<int, ConcurrentQueue<Page>> pages = 
     new ConcurrentDictionary<int, ConcurrentQueue<Page>>(); 

    public void Enqueue(int id, Page page) 
    { 
     var queue = this.pages.GetOrAdd(id, _ => new ConcurrentQueue<Page>()); 

     queue.Enqueue(page); 
    } 

    public bool TryDequeue(int id, out Page page) 
    { 
     ConcurrentQueue<Page> queue; 

     if (this.pages.TryGetValue(id, out queue)) 
     { 
      return queue.TryDequeue(out page); 
     } 

     page = null; 
     return false; 
    } 
} 
+0

+1 : 이것이 제가 제안하려고했던 것입니다. –

+0

"간단합니다", 훌륭한 대답은 – RuSh

-1

당신은 (그리고 아마도 것입니다) 이러한 진술의 문제에 실행할 수 있습니다 다음 ConcurrentDictionary

if (!this.pages.ContainsKey(id)) 
     this.pages[id] = new ConcurrentQueue<Page>(); 

if(this.pages.ContainsKey(id)) 
     this.pages[id].TryDequeue(out lp); 

을 할 수 사이에 바뀌다 if 문 및 할당/큐 제거. 같은 코드의 그 부분에 대한 잠금 오브젝트에 대한 잠금을 사용 @Femaref 올바르게 지적

public class PageQueue 
{ 
    private ConcurrentDictionary<int, ConcurrentQueue<Page>> pages = new ConcurrentDictionary<int, ConcurrentQueue<Page>>(); 
    private object locker = new object(); 

    public void Add(int id , Page page) 
    { 
     lock(locker) 
     { 
      if (!this.pages.ContainsKey(id)) 
       this.pages[id] = new ConcurrentQueue<Page>(); 
     } 

     this.pages[id].Enqueue(page); 
    } 

    public Page GetAndRemove(int id) 
    { 
     Page lp = null; 

     lock(locker) 
     { 
      if(this.pages.ContainsKey(id)) 
      this.pages[id].TryDequeue(out lp); 
     } 

     return lp; 
    } 
} 
+1

ConcurrentDictionary 많은 방법을 제공합니다 . 이것은 기본적으로 ConcurrentDictionary의 핵심입니다. – dtb

+0

thx Femaref, 나는 자물쇠를 추가해야한다는 것을 알고 있었지만 ConcurrentDictionary가 무언가를 가지고 있기를 바랬다. 나는 그럴 수 없다. – RuSh

+0

dtb, ConcurrentDictionary의 어떤 메소드를 제 코드에 맞출 수 있습니까? – RuSh

관련 문제