重建时阻止访问并发队列

问题描述

我有一个 ConcurrentQueue ,它包含一个带有一些帮助方法的对象,用于从队列中入队和出队。需要从队列中删除符合某些条件的项目,然后重建队列,因为它们可能不在第一个出队的项目中。

我怎样才能安全地做到这一点?

ConcurrentQueue 应该是线程安全的,但我还想防止在删除和重建发生时从队列中添加/删除项目。

我正在尝试这个,但我不确定它是否正确。

public class EmailRepository
{
    private readonly object _lockObj _lockObj = new object();
    private ConcurrentQueue<EmailMessage> _emailMessages = new ConcurrentQueue<EmailMessage>();

    public ConcurrentQueue<EmailMessage> EmailMessages => _emailMessages;

    public void AddEmailMessage(string subject,string body)
    {
        _emailMessages.Enqueue(new EmailMessage(subject,body));
    }

    public void AddEmailMessage(EmailMessage message)
    {
        _emailMessages.Enqueue(message);
    }

    public bool RemoveEmailMessage(out EmailMessage message)
    {
        return _emailMessages.TryDequeue(out message);
    }

    public void RemoveSiteEmailsAndRebuildQueue(int key)
    {
        for (int i = 0; i < _emailMessages.Count; i++)
        {
            RemoveEmailMessage(out EmailMessage message);
            if (message.keyvalue.Equals(key))
            {
                continue;
            }

            AddEmailMessage(message);
        }
    }
}

我暴露了 _emailMessages 但实际上没有任何修改集合,除非他们调用适当的方法

我认为我应该在 RemoveSiteEmailsAndRebuildQueue 的逻辑周围添加一些东西,以确保在该方法执行完成之前不会有任何内容入队或出队,但我不确定那是什么。

解决方法

你甚至可以不使用 ConcurrentQueue 而使用像这样的简单锁对象:

public class EmailRepository
{
    private readonly object _lockObj = new object();
    private Queue<EmailMessage> _emailMessages = new Queue<EmailMessage>();

    public Queue<EmailMessage> EmailMessages => _emailMessages;

    public void AddEmailMessage(string subject,string body)
    {
        lock (_lockObj)
        {
            _emailMessages.Enqueue(new EmailMessage(subject,body));
        }
    }

    public void AddEmailMessage(EmailMessage message)
    {
        lock (_lockObj)
        {
            AddWithoutLock(message);
        }
    }

    private void AddWithoutLock(EmailMessage message)
    {
        _emailMessages.Enqueue(message);

    }

    public bool RemoveEmailMessage(out EmailMessage message)
    {
        lock (_lockObj)
        {
            return _emailMessages.TryDequeue(out message);
        }
    }

    public void RemoveSiteEmailsAndRebuildQueue(int key)
    {
        lock (_lockObj)
        {
            for (int i = 0; i < _emailMessages.Count; i++)
            {
                RemoveEmailMessage(out EmailMessage message);
                if (message.KeyValue.Equals(key))
                {
                    continue;
                }

                AddWithoutLock(message);
            }
        }
    }
}