背景
我们的应用会发送在数据库表中排队的电子邮件。我们发送了一些重复电子邮件的实例,因此我实施了一个锁定,以防止多个线程同时发送电子邮件。
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.
}
答案 0 :(得分:5)
ReSharper无法告诉(或保证)SendQueuedMessage()
仅在同步块内调用。因此,就其而言,其他代码可能会在没有同步的情况下调用SendQueuedMessage()
,_mailQueueRepository
中正在使用SendQueuedMessage()
。
如果您确定没有其他代码(在包含类的内部或外部)调用此方法,或者您已确保所有来自类SendQueuedMessage()
的调用也已同步使用相同的锁定对象,你还好。如果你班级以外没有其他代码真的需要这种方法,我建议你把它变成私有。
答案 1 :(得分:4)
问题场景:
我们发送了一些重复电子邮件的实例,因此我正在实施一个锁定,以防止多个线程同时发送电子邮件。
所以你使用Lock()
来防止这种情况发生,这意味着你需要同步访问公共资源的线程,在这种情况下_mailQueueRepository
但是,在同一代码中,您使用的_mailQueueRepository
没有Lock
// I get the ReSharper warning here on _mailQueueRepository
var messageAttachments = _mailQueueRepository.GetMessageAttachments(message.Id); // <== Accessed without a lock
所以这是一个警告,告诉您有价值的资源是以两种不同的形式访问的:一个是synchronized
(线程安全),另一个是non-synchronized
(非线程安全)。
这是一个警告,让你 知道(或让你识别)资源_mailQueueRepository
的这种矛盾使用可能引起的问题。您可以选择使用_mailQueueRepository
synchronized
的所有用法(与lock
一起使用并且警告将消失)或管理不竞争条件。
此外,您可能会考虑重新构建代码,以便使用从SendQueuedMessage()
中提取的参数来调用_mailQueueRepository
,以避免混合使用。