重建时防止访问并发队列

Posted

技术标签:

【中文标题】重建时防止访问并发队列【英文标题】:Preventing access to concurrent queue while rebuilding 【发布时间】:2021-06-21 12:24:36 【问题描述】:

我有一个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 的逻辑周围添加一些东西,以确保在该方法执行完成之前没有任何东西会入队或出队,但我不确定那是什么。

【问题讨论】:

看起来向所有辅助函数添加锁定语句 (docs.microsoft.com/en-us/dotnet/csharp/language-reference/…) 就足够了。 【参考方案1】:

您甚至可以不使用 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);
            
        
    

【讨论】:

以上是关于重建时防止访问并发队列的主要内容,如果未能解决你的问题,请参考以下文章

如何防止 setState 在颤振中重建

MQ在高并发环境下,如果队列满了,如何防止消息丢失?

Flutter - 使用 MediaQuery 时防止重建

使用 yarn install 或 add 时防止包重建

Nginx限制访问速率和最大并发连接数模块--limit (防止DDOS攻击)

java处理高并发时,使用synchronized代码锁防止同时对数据库某一数据的问题。