【问题标题】:How to add a global lock to ASP.NET web application?如何为 ASP.NET Web 应用程序添加全局锁?
【发布时间】:2013-02-17 07:56:44
【问题描述】:

我正在使用 C# 编写一个 ASP.NET Web 应用程序,它可以从 IIS 服务器读取和写入文本文件(使用 System.IO.FileStream),我想知道如何在此操作上实现全局锁定?

【问题讨论】:

    标签: c# asp.net locking


    【解决方案1】:

    命名互斥体是系统对象。与 lock 关键字不同,它们甚至可以跨进程边界工作。锁只在同步同一进程中的线程的上下文中有用。

    【讨论】:

      【解决方案2】:

      根据@Aristos 的建议和this post,我想出了这个课程:

      using System.Threading;
      using System.Security.AccessControl;
      using System.Security.Principal;
      
      using System.Runtime.InteropServices;   //GuidAttribute
      using System.Reflection;                //Assembly
      
      namespace ITXClimateSaverWebApp
      {
          public class GlobalNamedLock
          {
              private Mutex mtx;
      
              public GlobalNamedLock(string strLockName)
              {
              //Name must be provided!
                  if(string.IsNullOrWhiteSpace(strLockName))
                  {
                      //Use default name
                      strLockName = ((GuidAttribute)Assembly.GetExecutingAssembly().GetCustomAttributes(typeof(GuidAttribute), false).GetValue(0)).Value.ToString();
                  }
      
                  //Create security permissions for everyone
                  //It is needed in case the mutex is used by a process with
                  //different set of privileges than the one that created it
                  //Setting it will avoid access_denied errors.
                  MutexSecurity mSec = new MutexSecurity();
                  mSec.AddAccessRule(new MutexAccessRule(new SecurityIdentifier(WellKnownSidType.WorldSid, null),
                      MutexRights.FullControl, AccessControlType.Allow));
      
                  //Create the global mutex
                  bool bCreatedNew;
                  mtx = new Mutex(false, @"Global\" + strLockName, out bCreatedNew, mSec);
              }
      
              public bool enterCRITICAL_SECTION()
              {
                  //Enter critical section
                  //INFO: May throw an exception!
                  //RETURN:
                  //      = 'true' if successfully entered
                  //      = 'false' if failed (DO NOT continue!)
      
                  //Wait
                  return mtx.WaitOne();
              }
      
              public void leaveCRITICAL_SECTION()
              {
                  //Leave critical section
                  //INFO: May throw an exception!
      
                  //Release it
                  mtx.ReleaseMutex();
              }
          }
      }
      

      然后是全局锁的调用方式:

      try
      {
          GlobalNamedLock gl = new GlobalNamedLock("MyLockName");
      
          try
          {
              if (gl.enterCRITICAL_SECTION())
              {
                  //Use the global resource now
              }
          }
          finally
          {
              gl.leaveCRITICAL_SECTION();
          }
      }
      catch (Exception ex)
      {
          //Failed -- log it
      }
      

      所以这似乎完成了这项工作。你怎么看?

      【讨论】:

      • 我建议使用其他名称,而不是 enterCRITICAL_SECTIONleaveCRITICAL_SECTION。在我能想象到的任何编程语言中,它们都是完全不可接受的。
      • 很多 main 代码比 C# 内置的“lock”关键字更复杂。
      • @CyanLite:对不起,什么?
      • @c00000fd:您正在重写与“lock”关键字完全相同的内容。
      • @CyanLite:如果我知道,我不会。顺便说一句,你怎么知道的?
      【解决方案3】:

      为什么不直接使用全局同步根对象?

      internal static class Lock
      {
          public static object SyncRoot = new object{};
      }
      

      用法:

      lock (Lock.SyncRoot)
      {
      }
      

      【讨论】:

      • 是不是因为这个静态锁对多个工作进程真的不起作用?
      • 这个答案实际上是错误的,并且在有多个工作进程的情况下不起作用。
      • @Ahmad:这个问题基本上没有提到“多个工作进程”,也没有提到所有其他答案。那你到底在说什么?
      • @abatishchev 它正在谈论全局锁,而您提供的方式在某些情况下不会这样做,这并不罕见。这就是我的观点。
      • @Ahmad:以上哪个答案适用多个工作进程?
      【解决方案4】:

      最简单的解决方案是在 Cache 或 Application 对象中创建一个新对象,最好是在 global.asax 文件中的 Application_Startup 中。如:

      Cache["myLocker"] = new object();
      

      然后你可以使用标准的“锁定”语法。

      lock(Cache["myLocker"]) 
      {
        // do file access here...
      }
      

      【讨论】:

      • Application 是我首先想到的。但有人告诉我一次,我喜欢这个想法,即此类是为经典 ASP 兼容性而提供的,实际上您不需要它,因为您可以使用更快的静态类来代替。
      【解决方案5】:

      全局锁需要mutex

          // The key can be part of the file name - 
          //   be careful not all characters are valid
          var mut = new Mutex(true, key);
      
          try
          {   
              // Wait until it is safe to enter.
              mut.WaitOne();
      
              // here you manipulate your file
          }
          finally
          {
              // Release the Mutex.
              mut.ReleaseMutex();
          }   
      

      【讨论】:

      • 谢谢。一个后续问题。我是否必须将“键”变量中的互斥锁名称设为 Global\key 才能在全球范围内读取?
      • @c00000fd 密钥,无论名称是什么,对计算机来说都是全局的。
      • 好的。我将它基于名为互斥体的 WinAPI(我相信这是“在内部”)。阅读lpName参数的描述:msdn.microsoft.com/en-us/library/windows/desktop/…
      • @c00000fd 我不明白你的意思。你能直接说出你的观点吗?
      猜你喜欢
      • 2011-05-31
      • 1970-01-01
      • 1970-01-01
      • 2021-07-14
      • 2012-03-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-01-26
      相关资源
      最近更新 更多