[英]Why does lock(this) thread.sleep not work with ASP.NET threading?
[英]Why this lock does not work in service, called from asp.net?
我继承了一个具有服务类的应用程序,该服务类是从asp.net应用程序调用的,如下所示:
class PeopleService : IPeopleService
{
//...
public void SavePerson(Person person)
{
person.UniqueId = _idGenerationService.GetNextId(person);
//...
_dbContext.InsertOrUpdate(person);
_dbContext.Commit();
}
}
class IdGenerationService : IIdGenerationService
{
//...
public string GetNextId(Person person)
{
int nextId = _dbContext.People.Count(x => x.Gender == person.Gender) + 1;
return string.Format("AB{0}", nextId);
}
}
GetNextId(Person)
的实现不是线程安全的,并且我们有很多具有重复ID的Person对象,例如AB1,AB2,AB2等。
解决方案是将lock
应用于SavePerson(Person)
如下所示:
class PeopleService : IPeopleService
{
private static readonly Object ReadIdLock = new Object();
//...
public void SavePerson(Person person)
{
lock(ReadIdLock)
{
person.UniqueId = _idGenerationService.GetNextId(person);
//...
_dbContext.InsertOrUpdate(person);
_dbContext.Commit();
}
}
}
现在,我们尝试通过在asp.net应用程序中同时单击“保存”按钮来测试代码。 但是修复没有用! 有趣的是,只有第一个记录似乎是重复的,例如AB1,AB1,AB2,AB3 ...
多个请求如何访问锁定的语句? 我应该改用Mutex
吗?
(请注意,该示例不是生产代码,它是一个简化的代码,可以传达我们遇到的问题。此外,一点点,我们将StructureMap用作DI)。
由于锁是一个静态变量,因此每个appdomain中只有一个这样的锁对象,它排除了许多可能的错误。 这是我能想到的唯一问题的原因:
您的锁只能在一个appdomain中使用。 ASP.NET可以同时在多个应用程序域中运行应用程序,例如在回收,部署或以网络花园模式运行时。 另外,您可能有多个服务器。
最好的解决方法是使_idGenerationService.GetNextId
线程安全的。 可能您需要对作为此方法基础的数据库查询应用适当的锁定。
另外,您锁定的区域太长。 您还将覆盖插入到数据库中。 这会使并发性不足,并可能导致分布式死锁。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.