网站建设移动网络公司,关键词网站排名查询,公司装修设计图片,中国化工网官网 网站建设场景是这样#xff0c;假设有一台设备会触发类型为Alarm的告警信号#xff0c;并把信号添加到一个Queue结构中#xff0c;每隔一段时间这个Queue会被遍历检查#xff0c;其中的每个Alarm都会调用一个相应的处理方法。问题在于#xff0c;检查机制是基于多线程的#xff0… 场景是这样假设有一台设备会触发类型为Alarm的告警信号并把信号添加到一个Queue结构中每隔一段时间这个Queue会被遍历检查其中的每个Alarm都会调用一个相应的处理方法。问题在于检查机制是基于多线程的有潜在的并发可能当某个Alarm被添加的同时刚好又在遍历Queue就会抛出异常说Queue发生改变。产生问题的代码如下public class AlarmQueueManager{ public ConcurrentQueueAlarm alarmQueue new ConcurrentQueueAlarm(); System.Timers.Timer timer; public AlarmQueueManager() { timer new System.Timers.Timer(1000); timer.Elapsed new System.Timers.ElapsedEventHandler(timer_Elapsed); timer.Enabled true; } void timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e) { DeQueueAlarm(); } private void DeQueueAlarm() { try { foreach (Alarm alarm in alarmQueue) { SendAlarm(alarm); alarmQueue.TryDequeue(); //having some trouble here with TryDequeue.. } } catch { } }}那么如何让DeQueueAlarm保证线程安全呢 为了简化描述用以下两种写法来对比介绍。// 写法一private void DeQueueAlarm(){ Alarm alarm; while (alarmQueue.TryDequeue(out alarm)) SendAlarm(alarm);} // 写法二private void DeQueueAlarm(){ foreach (Alarm alarm in alarmQueue) SendAlarm(alarm);}参考MSDN的说法ConcurrentQueueT.GetEnumerator 。The enumeration represents a moment-in-time snapshot of the contents of the queue. It does not reflect any updates to the collection after GetEnumerator was called. The enumerator is safe to use concurrently with reads from and writes to the queue.所以两种写法在多线程并发访问的差别就是使用TryQueue会确保每个Alarm只会被处理一次但哪个线程处理哪个Alarm是不确定的。使用foreach循环会确保参与争用的所有线程都同等无差别地访问Queue的全部Alarm就像Queue被重复处理了n遍。因此如果想要严格控制每个Alarm只会被处理一次用完就移除的话那就使用第一种写法。原文地址 http://www.cnblogs.com/BeanHsiang/p/8733059.html.NET社区新闻深度好文欢迎访问公众号文章汇总 http://www.csharpkit.com