2010-08-23 29 views
6

Aşağıdaki kodda .NET 4'ten ConcurrentDictionary ve ConcurrentQueue sınıflarını kullanıyorum.Bu ConcurrentDictionary ve ConcurrentQueue iş parçacığı güvenli midir?

Bu kod parçacığı güvenli mi? Eğer değilse, iplik güvenliğini nasıl sağlayabilirim?

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; 
    } 
} 

Demo:

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); 
    } 
} 

cevap

10

, kodunuzda bazı kusurları vardır. Sana lock ifadeleri için gerek kalmadan kod parçacığı güvenli hale getirmek için ConcurrentDictionary<K,V> sunduğu birçok yöntemden yararlanmak öneririz: Eğer ** ** `lock` kullanmak zorunda kalmamak

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: Tam olarak önereceğim şey buydu. –

+0

"kadar basit", büyük cevap thx. – RuSh

-1

Sen (ve muhtemelen olacaktır) bu ifadelere sorunlara çalışabilir: ConcurrentDictionary olarak

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

ve

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

can arasında değiştirilmek if deyimi ve Atama/Dequeue. gibi kod bu parçaların bir kilitleme nesne üzerinde bir kilit kullanın: @Femaref doğru belirttiği gibi

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 birçok yöntem sunar . Bu temelde ConcurrentDictionary'ın bütün noktası. – dtb

+0

thx Femaref, bir kilit eklemem gerektiğini biliyordum ama ConcurrentDictionary'ın bir şey yapması gerektiğini umuyordum, sadece yapamam. – RuSh

+0

dtb, ConcurrentDictionary yönteminin koduma uymasını sağlayabilir misiniz? – RuSh

İlgili konular