【问题标题】:ASP.NET lock thread methodASP.NET锁线程方法
【发布时间】:2010-03-30 10:33:50
【问题描述】:

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

谢谢

【问题讨论】:

    标签: c# asp.net multithreading methods locking


    【解决方案1】:

    mutex ctor 中将false 传递给initiallyOwned。如果您创建互斥体并最初拥有它,则需要再次调用ReleaseMutex

    【讨论】:

      【解决方案2】:

      您应该始终在释放互斥锁时尝试 finally。另外,请确保密钥正确(用户名)

      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;
      }
      

      【讨论】:

      • 谢谢,不添加 try/finally 确实是一个错误。但不幸的是,这不是问题的解决方案。
      【解决方案3】:

      在您的代码中,您正在懒惰地创建互斥锁。这会导致竞争条件。
      例如。当您从另一个线程调用 WaitOne() 时,可能会仅部分构造互斥锁。
      您也可能创建两个互斥体实例。
      等等……

      您可以通过急切地创建实例来避免这种情况 - 即在 Michael 的代码中。 (请务必将其初始化为非拥有状态。)

      Mutex 是内核级同步原语 - 它比 Monitor 更昂贵(这是 lock 使用的。

      【讨论】:

      • 你是对的,愚蠢的我没有想到这一点。它导致了我试图避免的相同问题(部分构造的订单)......感谢大家的回答。
      【解决方案4】:

      除非我遗漏了什么,你就不能用普通的锁吗?

      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;
          }
      }
      

      【讨论】:

      • 这也是我想到的,也许有人可以告诉我们互斥锁和锁之间的区别?我猜锁实际上只是表面之下的互斥锁,而您专门使用互斥锁来获得更多功能,但这只是猜测...
      • 嗨,也许我应该锁定。使用 Mutex 背后的想法是我只需要锁定每个用户名的方法。我想用一个名为 Mutex 来实现这一点。
      • 它是全局的——“一种同步原语,也可用于进程间同步”。您可以在同一台 PC 上的进程之间使用它 - 例如确保应用只启动一次...
      【解决方案5】:

      我一直避免锁定基于 Web 的应用程序 - 让 Web 服务器处理线程,而是构建重复检测。

      您认为锁定 CreateOrder 会得到什么?在我看来,您可能会避免同时创建两个订单,但最终还是会创建两个订单。

      【讨论】:

        【解决方案6】:

        这样做更容易:

        在某处定义一个类,如下所示:

        public class MyLocks {
            public static object OrderLock;
            static MyLocks() {
                OrderLock = new object();
            }
        }
        

        然后在使用锁时这样做:

        lock(MyLocks.OrderLock) {
            // put your code here
        }
        

        那么它不是很复杂。它的重量很轻,可以为任何目的定义锁,因为它们只是内存中非常小的对象,可以跨多个线程存活。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2011-09-11
          • 2013-08-19
          • 1970-01-01
          • 2014-09-20
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多