【发布时间】:2013-02-17 07:56:44
【问题描述】:
我正在使用 C# 编写一个 ASP.NET Web 应用程序,它可以从 IIS 服务器读取和写入文本文件(使用 System.IO.FileStream),我想知道如何在此操作上实现全局锁定?
【问题讨论】:
我正在使用 C# 编写一个 ASP.NET Web 应用程序,它可以从 IIS 服务器读取和写入文本文件(使用 System.IO.FileStream),我想知道如何在此操作上实现全局锁定?
【问题讨论】:
命名互斥体是系统对象。与 lock 关键字不同,它们甚至可以跨进程边界工作。锁只在同步同一进程中的线程的上下文中有用。
【讨论】:
根据@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_SECTION 和 leaveCRITICAL_SECTION。在我能想象到的任何编程语言中,它们都是完全不可接受的。
为什么不直接使用全局同步根对象?
internal static class Lock
{
public static object SyncRoot = new object{};
}
用法:
lock (Lock.SyncRoot)
{
}
【讨论】:
最简单的解决方案是在 Cache 或 Application 对象中创建一个新对象,最好是在 global.asax 文件中的 Application_Startup 中。如:
Cache["myLocker"] = new object();
然后你可以使用标准的“锁定”语法。
lock(Cache["myLocker"])
{
// do file access here...
}
【讨论】:
Application 是我首先想到的。但有人告诉我一次,我喜欢这个想法,即此类是为经典 ASP 兼容性而提供的,实际上您不需要它,因为您可以使用更快的静态类来代替。
全局锁需要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 才能在全球范围内读取?
lpName参数的描述:msdn.microsoft.com/en-us/library/windows/desktop/…