在同步块内部和外部使用字段是否安全?

Out*_*ill 8 .net c# resharper multithreading

背景

我们的应用程序发送在数据库表中排队的电子邮件.我们发送了一些重复电子邮件的实例,所以我实现了一个锁,以防止多个线程同时发送电子邮件.

ReSharper警告我:

该字段有时在同步块内使用,有时在没有同步的情况下使用

为什么ReSharper告诉我这个,为什么我会担心它?

这是我的(删节)代码:

private readonly IMailQueueRepository _mailQueueRepository = new MailQueueRepository();
private static object _messageQueueLock = new object();

public void SendAllQueuedMessages(IPrincipal caller)
{
    lock (_messageQueueLock) // Prevent concurrent callers
    {
        var message = _mailQueueRepository.GetUnsentMessage();
        while (message != null)
        {
            SendQueuedMessage(message);
            message = _mailQueueRepository.GetUnsentMessage();
        }
    }
}

public void SendQueuedMessage(IMessage message)
{
    // I get the ReSharper warning here on _mailQueueRepository
    var messageAttachments = _mailQueueRepository.GetMessageAttachments(message.Id);
    // etc.
}
Run Code Online (Sandbox Code Playgroud)

Wil*_*mpt 6

ReSharper无法告知(或保证)SendQueuedMessage()仅在同步块内调用.因此,就其而言,其他代码可能会在SendQueuedMessage()没有同步的情况下调用,并且_mailQueueRepository正在使用中SendQueuedMessage().

如果您确定没有其他代码(在包含类的内部或外部)调用此方法,或者您已确保类中的所有调用SendQueuedMessage()使用相同的锁对象进行同步,那么您就可以了.如果你班级以外没有其他代码真的需要这种方法,我建议你把它变成私有的.


Kav*_*uwa 6

问题场景:

我们已经发送了一些重复电子邮件的实例,因此我正在实现一个锁定,以防止多个线程同时发送电子邮件。

因此,您正在使用它Lock()来防止这种情况的发生,这意味着您需要同步访问公共资源的线程。 _mailQueueRepository

但同样,您使用的相同代码中_mailQueueRepository没有Lock

 // I get the ReSharper warning here on _mailQueueRepository
    var messageAttachments = _mailQueueRepository.GetMessageAttachments(message.Id); // <== Accessed without a lock
Run Code Online (Sandbox Code Playgroud)

因此,警告您以两种不同的形式访问您的宝贵资源是一种警告:一种synchronized(线程安全)和另一种non-synchronized(非线程安全)。

这是一个警告,告知 (或让您识别)此矛盾的资源使用可能引起的问题。您可以选择全部使用(使用和警告将消失),也可以选择不参加比赛。_mailQueueRepository_mailQueueRepository synchronizedlock

另外,您可能会考虑以重新构造代码的方式,使用SendQueuedMessage()_mailQueueRepository避免混合使用中提取的参数来调用您的代码。