确保线程安全下使用Queue的Enqueue和Dequeue

场景是这样,假设有一台设备会触发类型为Alarm的告警信号,并把信号添加到一个Queue结构中,每隔一段时间这个Queue会被遍历检查,其中的每个Alarm都会调用一个相应的处理方法。问题在于,检查机制是基于多线程的,有潜在的并发可能,当某个Alarm被添加的同时刚好又在遍历Queue,就会抛出异常说Queue发生改变。产生问题的代码如下:

public class AlarmQueueManager

{

    public ConcurrentQueue<Alarm> alarmQueue = new ConcurrentQueue<Alarm>();

    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的说法:ConcurrentQueue<T>.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

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值