我正在使用C#开发ASP.NET表单Web应用程序。我有一种为客户创建新订单的方法。它看起来与此相似;
private string CreateOrder(string userName) {
// Fetch current order
Order order = FetchOrder(userName);
if (order.OrderId == 0) {
// Has no order yet, create a new one
order.OrderNumber = Utility.GenerateOrderNumber();
order.Save();
}
return order;
}
这里的问题是,两个请求(线程)中的1个客户可能会导致此方法被调用两次,而另一个线程也在此方法中。这可能导致创建两个订单。
如何正确锁定此方法,因此每个客户一次只能由一个线程执行?
我试过了;
Mutex mutex = null;
private string CreateOrder(string userName) {
if (mutex == null) {
mutex = new Mutex(true, userName);
}
mutex.WaitOne();
// Code from above
mutex.ReleaseMutex();
mutex = null;
return order;
}
这样可行,但在某些情况下它挂在WaitOne上,我不知道为什么。是否有错误,或者我应该使用其他方法来锁定?
由于
答案 0 :(得分:1)
在发布互斥锁时,您应该始终最后尝试。此外,请确保密钥正确(userName)
Mutex mutex = null;
private string CreateOrder(string userName) {
mutex = mutex ?? new Mutex(true, userName);
mutex.WaitOne();
try{
// Code from above
}finally{
mutex.ReleaseMutex();
}
mutex = null;
return order;
}
答案 1 :(得分:1)
在您的代码中,您正懒惰地创建互斥锁。这会导致竞争条件 例如。当你从另一个线程调用WaitOne()时,可能会发生部分构造互斥锁 您也可能会创建两个互斥锁实例 等...
您可以通过热切地创建实例来避免这种情况 - 例如在Michael的代码中。 (务必将其初始化为非拥有状态。)
Mutex是一个内核级同步原语 - 它比Monitor更贵(这是lock
使用的。)。
答案 2 :(得分:1)
在false
ctor中传递initiallyOwned
mutex
。如果您创建了互斥锁并且最初拥有互斥锁,则需要再次调用ReleaseMutex
。
答案 3 :(得分:0)
除非我遗漏了什么,否则你不能只使用常规锁?
private object _locker = new object();
private string CreateOrder(string userName)
{
lock(_locker)
{
// Fetch current order
Order order = FetchOrder(userName);
if (order.OrderId == 0)
{
// Has no order yet, create a new one
order.OrderNumber = Utility.GenerateOrderNumber();
order.Save();
}
return order;
}
}
答案 4 :(得分:0)
我一直避免锁定基于Web的应用程序 - 让Web服务器处理线程,而是构建重复检测。
您认为通过锁定CreateOrder会得到什么?在我看来,你可以避免同时创建两个订单,但你仍然会最终创建两个订单。
答案 5 :(得分:0)
更容易做到这一点:
在某处定义一个类:
public class MyLocks {
public static object OrderLock;
static MyLocks() {
OrderLock = new object();
}
}
然后在使用锁时执行此操作:
lock(MyLocks.OrderLock) {
// put your code here
}
那不是很复杂。它的重量很轻,无论出于何种目的都可以定义锁,因为它们只是内存中非常小的对象,可以在多个线程中存活。