我有一个web应用程序,它控制哪些web应用程序从我们的负载平衡器获得服务流量。 Web应用程序在每台服务器上运行。C# - 锁定互斥锁问题
它跟踪ASP.NET应用程序状态下对象中每个应用程序的“进入或退出”状态,并且每当状态发生更改时,该对象就会序列化到磁盘上的文件。当Web应用程序启动时,状态将从文件反序列化。
尽管网站本身只获得了几秒钟的请求,而且很少访问该文件,但我发现在尝试从文件读取或写入文件时出于某种原因得到冲突非常容易。这种机制需要非常可靠,因为我们有一个自动化系统,可以定期将部署部署到服务器。
在任何人发表任何评论质疑上述任何一条之前,请允许我简单地说,解释背后的理由会使这篇文章比以前更长,所以我想避免移山。
也就是说,我用它来控制访问该文件的代码如下所示:
internal static Mutex _lock = null;
/// <summary>Executes the specified <see cref="Func{FileStream, Object}" /> delegate on
/// the filesystem copy of the <see cref="ServerState" />.
/// The work done on the file is wrapped in a lock statement to ensure there are no
/// locking collisions caused by attempting to save and load the file simultaneously
/// from separate requests.
/// </summary>
/// <param name="action">The logic to be executed on the
/// <see cref="ServerState" /> file.</param>
/// <returns>An object containing any result data returned by <param name="func" />.
///</returns>
private static Boolean InvokeOnFile(Func<FileStream, Object> func, out Object result)
{
var l = new Logger();
if (ServerState._lock.WaitOne(1500, false))
{
l.LogInformation("Got lock to read/write file-based server state."
, (Int32)VipEvent.GotStateLock);
var fileStream = File.Open(ServerState.PATH, FileMode.OpenOrCreate
, FileAccess.ReadWrite, FileShare.None);
result = func.Invoke(fileStream);
fileStream.Close();
fileStream.Dispose();
fileStream = null;
ServerState._lock.ReleaseMutex();
l.LogInformation("Released state file lock."
, (Int32)VipEvent.ReleasedStateLock);
return true;
}
else
{
l.LogWarning("Could not get a lock to access the file-based server state."
, (Int32)VipEvent.CouldNotGetStateLock);
result = null;
return false;
}
}
这通常作品,但偶尔我无法访问互斥(我看到“莫非在日志中没有得到锁定“事件)。我无法在本地重现 - 它只发生在我的生产服务器上(Win Server 2k3/IIS 6)。如果我删除超时,则应用程序无限期挂起(争用条件??),包括后续请求。
当我确实发现错误时,查看事件日志告诉我,互斥锁已被上一个请求发布,并在之前记录错误。
该互斥量在Application_Start事件中被实例化。当它在声明中静态实例化时,我会得到相同的结果。
借口,借口:线程/锁定不是我的工作,因为我通常不必担心它。
任何有关为什么它会随机无法获得信号的建议?
更新:
我已经添加适当的错误处理(多么尴尬!),但我仍然得到同样的错误 - 并记录在案,未处理的异常从来不是问题。
只有一个进程会访问该文件 - 我没有为此应用程序的Web池使用Web园,也没有其他应用程序使用该文件。我能想到的唯一例外是应用程序池回收时,旧WP在创建新WP时仍处于打开状态 - 但通过观察任务管理器可以看出,只有一个工作进程存在问题。
@mmr:如何使用Monitor与使用Mutex不同?基于MSDN文档,它看起来像是有效地做同样的事情 - 如果我无法获得我的互斥锁的锁,它确实只是返回false失败。
另一件需要注意的事情:我遇到的问题似乎完全是随机的 - 如果一个请求失败,它可能在下一个工作正常。似乎没有一种模式,至少(至少绝对不是)。
更新2:
此锁不用于任何其他呼叫。在InvokeOnFile方法之外引用_lock的唯一时间是实例化时。
被调用的Func是从文件中读取并反序列化成一个对象,或者序列化一个对象并将其写入文件。这两个操作都不在一个单独的线程上完成。
ServerState.PATH是一个静态只读字段,我不认为会导致任何并发问题。
我还想重申一下我以前的观点,我无法在本地重现(卡西尼)。
教训:
- 使用正确的错误处理(!咄)
- 使用了合适的工具(并有该工具怎么样呢/一个基本的了解) 。正如sambo指出的那样,使用Mutex显然有很多开销,这导致我的应用程序出现问题,而Monitor是专门为.NET设计的。
文件是单个文件在两个服务器之间共享还是每个服务器单个文件? – 2009-01-15 22:26:19
每个服务器的单个文件。 – 2009-01-15 22:27:46