场景是这样,假设有一台设备会触发类型为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();
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只会被处理一次,用完就移除的话,那就使用第一种写法。

原文:Thread safe queue - Enqueue / Dequeue

确保线程安全下使用Queue的Enqueue和Dequeue的更多相关文章

  1. java线程安全之并发Queue

    关闭 原 java线程安全之并发Queue(十三) 2017年11月19日 23:40:23 小彬彬~ 阅读数:12092更多 所属专栏: 线程安全    版权声明:本文为博主原创文章,未经博主允许不 ...

  2. 获取其他线程的数据用 queue, 多进程Q

    获取其他线程的数据用 queue, 多进程Q

  3. tensorflow队列tf.FIFOQueue | enqueue | enqueue_many | dequeue | dequeue_many

    关于队列的相关知识,盗用一张https://blog.csdn.net/HowardWood/article/details/79406891的动态图 import tensorflow as tf ...

  4. Perl线程队列:Thread::Queue

    (Thread::Queue)队列数据结构(FIFO)是线程安全的,它保证了某些线程从一端写入数据,另一些线程从另一端读取数据.只要队列已经满了,写入操作就自动被阻塞直到有空间支持写操作,只要队列空了 ...

  5. python 线程之 数据同步 Queue

    Queue:将数据从一个线程发往另外一个线程比较通用的方式是使用queue模块的Queue类 1, 首先创建一个Queue模块的对象,创建Queue对象可以传递maxsize也可以不传递 2. 使用对 ...

  6. 装个蒜。学习下dispatch queue

    dispatch queue的真髓:能串行,能并行,能同步,能异步以及共享同一个线程池. 接口: GCD是基于C语言的APT.虽然最新的系统版本中GCD对象已经转成了Objective-C对象,但AP ...

  7. 三种进程和线程数据共享模块方法Queue》Pipe》manager

    >>>>线程中的queue import threading import queue def f(qq): print("in child",qq.qsi ...

  8. 多线程深入理解和守护线程、子线程、锁、queue、evenet等介绍

    1.多线程类的继承 import threading import time class MyThreading(threading.Thread): def __init__(self,n): su ...

  9. 进程与线程的通信机制----Queue

    进程运行时候变量是隔离的,线程间共享全局变量. 进程: from multiprocessing import Process from threading import Thread def get ...

随机推荐

  1. 【慕课网实战】Spark Streaming实时流处理项目实战笔记三之铭文升级版

    铭文一级: Flume概述Flume is a distributed, reliable, and available service for efficiently collecting(收集), ...

  2. Redis-5.0.0集群配置

    版本:redis-5.0.0 参考:http://redis.io/topics/cluster-tutorial. 集群部署交互式命令行工具:https://github.com/eyjian/re ...

  3. 笔记本真机安装centos7

    突然有一天,想要装linux系统,所以就是去装,网上百度说的都很多,而且说来说去都是那几篇,大同小异,所以想通过自己本次装真机的一些经验提供给各位朋友参考一下. 一安装系统: 1先制作启动盘,用个比较 ...

  4. 标记化结构初始化语法 在结构体成员前加上小数点 如 “.open .write .close ”C99编译器 .

    今天在看串口驱动(四)的时候 有这样一个结构体初始化 我很不理解 如下: static struct s3c24xx_uart_port s3c24xx_serial_ports[NR_PORTS] ...

  5. QT中的线程与事件循环理解(1)

    1.需要使用多线程管理的例子 一个进程可以有一个或更多线程同时运行.线程可以看做是“轻量级进程”,进程完全由操作系统管理,线程即可以由操作系统管理,也可以由应用程序管理.Qt 使用QThread 来管 ...

  6. hdu 1059

    题目大意:就是有价值1.2.3.4.5.6的硬币各多少个,然后让你判断能否把他们分成价值相等的两部分. 题目思路:目测dp,一看果然dp,完全背包,需要剪枝,硬币个数为容量,下标为value,用一个b ...

  7. SRM480

    250pt: 题意:给定n个网站,以及n个网站的关键词,还有一个危险词库.如果一个网站的关键词中>=th的危险词,那么这个网站便是危险的.同时,他的所有关键词加入危险词库.问,有多少个危险网站. ...

  8. 使用EF操作Oracle数据库小计

    1.建表 CREATE TABLE item.ORDERS( ORDERID ) CONSTRAINT PK_ORDERS PRIMARY KEY, ORDERNO ), STOREID ), STO ...

  9. Excel VBA语句集

    Excel VBA语句集 引子 最近批阅学生成绩,用Excel 处理学生成绩,用到VBA 提高办公效率.需要经常查阅VBA的一些用法 正文 定制模块行为 (1) Option Explicit '强制 ...

  10. Hibernate在PostgreSQL上执行sum函数导致数据失真的问题

    有一段通过Hibernate从PostgreSQL上进行sum统计的简单代码,但统计结果却导致数据失真,不知原因何在,求指教! Java代码片段如下: public List<Object> ...