这是ConcurrentDictionary和ConcurrentQueue线程安全的组合吗?
我在以下代码中使用.NET 4中的ConcurrentDictionary和ConcurrentQueue类。
这段代码是线程安全的吗? 如果没有,我怎样才能使它成为线程安全的?
public class Page { public string Name {get; set; } } public class PageQueue { private ConcurrentDictionary<int, ConcurrentQueue> pages = new ConcurrentDictionary<int, ConcurrentQueue>(); public void Add(int id, Page page) { if (!this.pages.ContainsKey(id)) this.pages[id] = new ConcurrentQueue(); 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 Run()); } public void Run() { PageQueue pq = new PageQueue(); pq.Add(1, new Page()); pq.GetAndRemove(1); } }
正如@Femaref正确指出的那样,代码中存在一些缺陷。 我建议您利用ConcurrentDictionary lock
语句:
public class PageQueue { private ConcurrentDictionary> pages = new ConcurrentDictionary>(); public void Enqueue(int id, Page page) { var queue = this.pages.GetOrAdd(id, _ => new ConcurrentQueue ()); queue.Enqueue(page); } public bool TryDequeue(int id, out Page page) { ConcurrentQueue queue; if (this.pages.TryGetValue(id, out queue)) { return queue.TryDequeue(out page); } page = null; return false; } }
您可以(也可能会)遇到这些语句的问题:
if (!this.pages.ContainsKey(id)) this.pages[id] = new ConcurrentQueue();
和
if(this.pages.ContainsKey(id)) this.pages[id].TryDequeue(out lp);
因为可以在if语句和Assignment / Dequeue之间更改ConcurrentDictionary
。 对锁定对象使用锁定代码的那些部分,例如:
public class PageQueue { private ConcurrentDictionary> pages = new ConcurrentDictionary>(); private object locker = new object(); public void Add(int id , Page page) { lock(locker) { if (!this.pages.ContainsKey(id)) this.pages[id] = new ConcurrentQueue (); } 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; } }