c# – 线程安全队列 – 入队/出队

首先,我将解释一个短暂的场景;

作为来自某些设备触发的信号,将一个类型为Alarm的对象添加到队列中.在一个间隔,队列被检查,并且对于队列中的每个警报,它触发一个方法.

但是,我遇到的问题是,如果在队列中被添加了一个警报,则会在队列中被使用时发出错误.这里有一些代码来显示我的队列,只是假设警报正在被不断的插入;

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

所以我的问题是,我如何使这更多…线程安全?所以我不会遇到这些问题.也许是沿着这样的方式,将队列复制到另一个队列中,然后对该队列进行处理,然后将从原队列处理的报警排队?

编辑:刚刚被通知并发队列,现在就检查一下

最佳答案
private void DeQueueAlarm()
{
    Alarm alarm;
    while (alarmQueue.TryDequeue(out alarm))
        SendAlarm(alarm);
}

或者,您可以使用:

private void DeQueueAlarm()
{
    foreach (Alarm alarm in alarmQueue)
        SendAlarm(alarm);
}

根据07年的MSDN文章:

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.

因此,当您的DeQueueAlarm方法由多个线程同时调用时,两种方法之间的区别就会出现.使用TryQueue方法,您可以确保队列中的每个报警只能处理一次;然而,哪个线程选择哪个报警是非确定的. foreach方法确保每个赛车线程将处理队列中的所有警报(从它开始迭代到它的时间点),导致相同的警报被多次处理.

如果要对每个报警进行一次处理,然后将其从队列中删除,则应使用第一种方法.

转载注明原文:c# – 线程安全队列 – 入队/出队 - 代码日志