ASP.NET锁线程方法

时间:2010-03-30 10:33:51

标签: c# asp.net multithreading methods locking

我正在使用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上,我不知道为什么。是否有错误,或者我应该使用其他方法来锁定?

由于

6 个答案:

答案 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
}

那不是很复杂。它的重量很轻,无论出于何种目的都可以定义锁,因为它们只是内存中非常小的对象,可以在多个线程中存活。