C# - 锁定与互斥问题 [英] C# - Locking issues with Mutex

查看:202
本文介绍了C# - 锁定与互斥问题的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我已经得到了控制哪些Web应用程序获得服务从我们的负载均衡器的流量的Web应用程序。 Web应用程序运行的每个单独的服务器上。

I've got a web application that controls which web applications get served traffic from our load balancer. The web application runs on each individual server.

它跟踪了或退出状态的在ASP.NET应用程序状态的对象每个应用程序,并且每当状态改变的对象是序列化到磁盘上的文件。 Web应用程序启动时的状态是从文件反序列化。

It keeps track of the "in or out" state for each application in an object in the ASP.NET application state, and the object is serialized to a file on the disk whenever the state is changed. The state is deserialized from the file when the web application starts.

虽然网站本身只得到一对夫妇请求第二上衣,并且它很少被访问文件时,我发现这是非常容易因为某些原因让冲突试图读取或写入文件。这种机制需要非常可靠的,因为我们有一个自动化系统,可定期做滚动部署到服务器。

While the site itself only gets a couple requests a second tops, and the file it rarely accessed, I've found that it was extremely easy for some reason to get collisions while attempting to read from or write to the file. This mechanism needs to be extremely reliable, because we have an automated system that regularly does rolling deployments to the server.

有人质疑,使上述任何的谨慎任何评论之前,请允许我简单地说,解释的理由背后它将使这个职位比现在要长得多,所以我想避免移山。

Before anyone makes any comments questioning the prudence of any of the above, allow me to simply say that explaining the reasoning behind it would make this post much longer than it already is, so I'd like to avoid moving mountains.

这是说,我用它来控制访问该文件的code是这样的:

That said, the code that I use to control access to the file looks like this:

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

此的一般的工作,但偶尔我无法访问互斥(我看到在日志中的无法得到锁事件)。我无法在本地重现此 - 它只是发生在我的生产服务器(赢服务器2K3 / IIS 6)。如果我删除了超时,应用程序无限期挂起(竞争状态?),其中包括在后续请求。

This usually works, but occasionally I cannot get access to the mutex (I see the "Could not get a lock" event in the log). I cannot reproduce this locally - it only happens on my production servers (Win Server 2k3/IIS 6). If I remove the timeout, the application hangs indefinitely (race condition??), including on subsequent requests.

当我得到的错误,看着事件日志告诉我,互斥锁达到并通过previous要求的的被记录的错误释放。

When I do get the errors, looking at the event log tells me that the mutex lock was achieved and released by the previous request before the error was logged.

该互斥锁在Application_Start事件中实例化。我得到相同的结果时,它在声明静态实例。

The mutex is instantiated in the Application_Start event. I get the same results when it is instantiated statically in the declaration.

找借口,找借口:线程/锁定是不是我的专长,我一般不用担心它

Excuses, excuses: threading/locking is not my forté, as I generally don't have to worry about it.

任何建议,为什么它会随机取不到信号?

Any suggestions as to why it randomly would fail to get a signal?


更新:

我添加适当的错误处理(多么尴尬!),但我仍然得到同样的错误 - 并记录在案,未处理的异常从来不是问题。

I've added proper error handling (how embarrassing!), but I am still getting the same errors - and for the record, unhandled exceptions were never the problem.

只有一个进程将永远是访问文件 - 我不使用Web园为这个应用程序的Web池,并没有其他应用程序使用的文件。我能想到的唯一的例外是当应用​​程序池回收,并创建新的之一,当旧的WP仍然是开放的 - 但我可以从看任务管理器,虽然只有一个工作进程出现问题告诉我们。

Only one process would ever be accessing the file - I don't use a web garden for this application's web pool, and no other applications use the file. The only exception I can think of would be when the app pool recycles, and the old WP is still open when the new one is created - but I can tell from watching the task manager that the issue occurs while there is only one worker process.

@mmr:如何使用监控使用互斥有什么不同?根据MSDN文档上,它看起来是有效地做同样的事情 - 如果我不能用我的互斥获得锁,它的确实的只需返回false失败摆好

@mmr: How is using Monitor any different from using a Mutex? Based on the MSDN documentation, it looks like it is effectively doing the same thing - if and I can't get the lock with my Mutex, it does fail gracefully by just returning false.

另外一点需要注意的:我有这些问题似乎是完全随机的 - 如果它失败的一个请求,它可能做工精细的下一个。似乎没有成为一个模式,或者(肯定没隔,至少)。

Another thing to note: The issues I'm having seem to be completely random - if it fails on one request, it might work fine on the next. There doesn't seem to be a pattern, either (certainly no every other, at least).


更新2:

这锁不用于其他任何电话。唯一的一次_lock引用外InvokeOnFile方法是当它被实例化。

This lock is not used for any other call. The only time _lock is referenced outside the InvokeOnFile method is when it is instantiated.

这是调用从文件是读取和反序列化到对象或序列化对象,并将其写入文件中的函数功能。无论操作是在一个单独的线程中完成的。

The Func that is invoked is either reading from the file and deserializing into an object, or serializing an object and writing it to the file. Neither operation is done on a separate thread.

ServerState.PATH是一个静态只读域,这是我不希望会造成任何并发问题。

ServerState.PATH is a static readonly field, which I don't expect would cause any concurrency problems.

我也想再次重申我之前的观点,我不能在本地复制本(在卡西尼)。


I'd also like to re-iterate my earlier point that I cannot reproduce this locally (in Cassini).


经验教训:


  • 使用正确的错误处理(废话!)

  • 使用了合适的工具(并有该工具如何做什么/一个基本的了解)。三宝指出,使用互斥显然有很大的开销,这是导致我的应用程序的问题,而监视器用于.NET专门设计的。

推荐答案

如果你需要的跨进程同步

虽然互斥可用于
  进程内的线程同步,
  采用监控一般是preferred,
  因为显示器在设计
  专门为.NET Framework
  因此,更好地利用
  资源。与此相反,互斥
  类是一个包装到Win32
  构造。虽然这是更强大的
  比监视器,需要互斥
  互操作转换那些更
  计算上比那些昂贵的
  由Monitor类必需的。

Although a mutex can be used for intra-process thread synchronization, using Monitor is generally preferred, because monitors were designed specifically for the .NET Framework and therefore make better use of resources. In contrast, the Mutex class is a wrapper to a Win32 construct. While it is more powerful than a monitor, a mutex requires interop transitions that are more computationally expensive than those required by the Monitor class.

如果您需要支持跨进程锁定你需要一个<一个href=\"http://stackoverflow.com/questions/229565/what-is-a-good-pattern-for-using-a-global-mutex-in-c\">Global互斥。

If you need to support inter-process locking you need a Global mutex.

所使用的模式是令人难以置信的脆弱,没有任何异常处理和你没有确保您的Mutex被释放。这确实是有风险的code,最有可能你看到这些的时候挂起,没有超时的原因。

The pattern being used is incredibly fragile, there is no exception handling and you are not ensuring that your Mutex is released. That is really risky code and most likely the reason you see these hangs when there is no timeout.

另外,如果你的文件操作曾经花费超过1.5秒时则有机会同时互斥体将无法抓住它。我会建议得到正确的上锁,避免超时。

Also, if your file operation ever takes longer than 1.5 seconds then there is a chance concurrent Mutexes will not be able to grab it. I would recommend getting the locking right and avoiding the timeout.

我认为它最好重新写这个使用锁。此外,它看起来像你呼唤另一种方法,如果这永远拿,锁将永远保持。这是pretty风险。

I think its best to re-write this to use a lock. Also, it looks like you are calling out to another method, if this take forever, the lock will be held forever. That's pretty risky.

这是既短,更安全:

        // if you want timeout support use 
        // try{var success=Monitor.TryEnter(m_syncObj, 2000);}
        // finally{Monitor.Exit(m_syncObj)}
        lock(m_syncObj)
        {
            l.LogInformation("Got lock to read/write file-based server state.", (Int32)VipEvent.GotStateLock);
            using (var fileStream = File.Open(ServerState.PATH, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.None))
            {
                // the line below is risky, what will happen if the call to invoke
                // never returns? 
                result = func.Invoke(fileStream);
            }
        }

        l.LogInformation("Released state file lock.", (Int32)VipEvent.ReleasedStateLock);
        return true;

        // note exceptions may leak out of this method. either handle them here.
        // or in the calling method. 
        // For example the file access may fail of func.Invoke may fail

这篇关于C# - 锁定与互斥问题的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆