C# - 互斥锁的锁定问题

2024-04-11

我有一个 Web 应用程序,可以控制哪些 Web 应用程序从我们的负载均衡器获取服务流量。 Web 应用程序在每个单独的服务器上运行。

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

This usually有效,但有时我无法访问互斥体(我在日志中看到“无法获取锁定”事件)。我无法在本地重现此问题 - 它只发生在我的生产服务器(Win Server 2k3/IIS 6)上。如果我删除超时,应用程序将无限期挂起(竞争条件??),包括后续请求。

当我确实收到错误时,查看事件日志会告诉我互斥锁已由前一个请求实现并释放before错误已被记录。

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

借口,借口:线程/锁定不是我的强项,因为我通常不必担心它。

关于为什么它随机无法收到信号有什么建议吗?


Update:

我已经添加了正确的错误处理(多么尴尬!),但我仍然遇到相同的错误 - 并且根据记录,未处理的异常从来都不是问题。

只有一个进程会访问该文件 - 我不使用网络花园作为该应用程序的网络池,并且没有其他应用程序使用该文件。我能想到的唯一例外是当应用程序池回收时,并且在创建新的 WP 时旧的 WP 仍然处于打开状态 - 但我可以通过观察任务管理器看出问题是在只有一个工作进程时发生的。

@mmr:使用 Monitor 与使用 Mutex 有什么不同?根据 MSDN 文档,看起来它实际上在做同样的事情 - 如果我无法使用我的互斥体获得锁,那么它does只需返回 false 即可优雅地失败。

另一件需要注意的事情是:我遇到的问题似乎完全是随机的 - 如果一个请求失败,那么下一个请求可能会正常工作。似乎也没有任何模式(至少没有其他模式)。


更新2:

该锁不用​​于任何其他调用。唯一一次在 InvokeOnFile 方法外部引用 _lock 是在实例化它时。

调用的 Func 要么从文件读取并反序列化为对象,要么序列化对象并将其写入文件。这两个操作都不是在单独的线程上完成的。

ServerState.PATH 是一个静态只读字段,我预计它不会导致任何并发问题。

我还想重申我之前的观点,即我无法在本地(在卡西尼号)中重现这一点。


得到教训:

  • 使用正确的错误处理(废话!)
  • 使用正确的工具来完成工作(并对该工具的作用/作用有基本的了解)。正如 sambo 指出的那样,使用 Mutex 显然会产生大量开销,这会导致我的应用程序出现问题,而 Monitor 是专门为 .NET 设计的。

您应该仅在需要时使用互斥体跨进程同步.

尽管互斥锁可用于 进程内线程同步, 通常首选使用 Monitor, 因为显示器的设计 专门针对 .NET Framework 从而更好地利用 资源。相比之下,互斥体 类是 Win32 的包装 构造。虽然它更强大 与监视器相比,互斥锁需要 互操作转换更多 计算成本比那些 Monitor 类需要。

如果您需要支持进程间锁定,您需要全局互斥体 https://stackoverflow.com/questions/229565/what-is-a-good-pattern-for-using-a-global-mutex-in-c.

所使用的模式非常脆弱,没有异常处理,并且您无法确保释放互斥体。这确实是有风险的代码,很可能是您在没有超时的情况下看到这些挂起的原因。

另外,如果您的文件操作花费的时间超过 1.5 秒,那么并发互斥体有可能无法获取它。我建议正确锁定并避免超时。

我认为最好重写它以使用锁。另外,看起来您正在调用另一个方法,如果这需要永远,那么锁将永远保持。那是相当危险的。

这既更短又更安全:

// 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
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

C# - 互斥锁的锁定问题 的相关文章

  • 为什么迭代器类型推导失败? [复制]

    这个问题在这里已经有答案了 为什么这在 C 中不起作用 为什么我不能限制foo的参数为std vector
  • ptrace和waitpid有什么关系?

    我正在练习使用ptrace但我不太了解它和之间的关系waitpid 这是我的测试程序 int main int argc char argv pid t pid 22092 if ptrace PTRACE ATTACH pid NULL
  • C# 中输入按键

    我尝试了这段代码 private void textBox1 KeyPress object sender KeyPressEventArgs e if Convert ToInt32 e KeyChar 13 MessageBox Sho
  • 这种对有效类型规则的使用是否严格遵守?

    C99和C11中的有效类型规则规定 没有声明类型的存储可以用任何类型写入 并且存储非字符类型的值将相应地设置存储的有效类型 抛开 INT MAX 可能小于 123456789 的事实不谈 以下代码对有效类型规则的使用是否严格符合 inclu
  • 自动 IIS6 403.4 重定向到 SSL 不起作用

    我的 ASP Net 网站中有一个目录需要启用 SSL 对于所有其他目录 我不希望启用 SSL 使用 IIS 我为我想要需要 SSL 的文件夹选中了 需要安全通道 SS 和 128 位加密复选框 现在 当用户在我的安全目录中输入 http
  • 如何在控制器中使用多个 DBContext

    如何在控制器中使用多个 DBContext 我尝试以不同的方式重载构造函数 一些控制器 public C1 DBContext1 a DBContext2 b DBContext3 c public C1 DBContext1 a publ
  • 如何检查给定调用站点的重载决策集

    如何检查重载解析集 我在多个调用站点中使用了 4 个相互竞争的函数 在一个调用站点中 我期望调用一个函数 但编译器会选择另一个函数 我不知道为什么 这不是微不足道的 为了了解发生了什么 我正在使用enable if disable if打开
  • 如何在 NUnit 测试中使用 Selenium 获取 javascript 日志?

    我正在尝试使用 Selenium ChromeDriver 从 Visual Studio 上的 NUnit 测试中检索 Javascript 控制台日志 但我在日志上得到空值 我已经尝试了下面的代码 但它会在 driver Manage
  • 如何使用 Selenium Webdriver .NET 绑定设置 Chrome 首选项?

    这是我正在使用的 用户代理可以成功设置 而下载首选项则不能 Windows 7 Chrome 26 Selenium dotnet 2 31 2 chromedriver win 26 0 1383 0 ChromeOptions chro
  • 代码块 - 使用大地址感知标志进行编译

    如何使用以下命令在 64 位系统上编译 32 位应用程序LARGE ADRESS AWARE使用代码块标记 我需要使用超过 2GB 的内存 应该是添加的情况 Wl large address aware到链接标志 我不使用 CodeBloc
  • 是否可以在对Where 的调用中调用命名方法?

    我试图从 RedGate 的这本免费电子书中了解 Linq 的一些性能影响ftp support red gate com ebooks under the hood of net memory management part1 pdf f
  • VS C# 中的依赖地狱,找不到依赖项

    我创建了一个图表 C 库 我们称之为chartlibrary 它本身依赖于多个第三方 dll 文件 在另一个可执行项目中 我们称之为chartuser 我参考了chartlibrary项目 两个项目位于 Visual Studio 中的同一
  • 为什么 std::atomic 比 volatile bool 慢很多?

    多年来我一直使用 volatile bool 来控制线程执行 并且效果很好 in my class declaration volatile bool stop In the thread function while stop do th
  • 这个元组创建习惯有名字吗?

    On the 增加邮件列表 http lists boost org Archives boost 2014 06 214213 php LouisDionne 最近发布了以下创建类似元组的实体的巧妙技巧 include
  • 我应该使用 Helgrind 还是 DRD 进行线程错误检测?

    好像Valgrind http valgrind org docs manual manual html有两个工具都可以进行线程错误检测 Helgrind http valgrind org docs manual hg manual ht
  • C# 中的类和模块有什么用

    有人可以解释一下类和模块之间的区别吗 你什么时候使用其中一种而不是另一种 我正在使用 C 更新 我的意思是相当于 VB 模块的 C 版本 这在很大程度上取决于您所指的 模块 Visual Basic 的模块 C 中没有真正等效的 VB Ne
  • 从 cin 读取整数序列并将它们存储在向量中

    这就是我读取整数的方法std cin并将它们存储在向量中 int number vector
  • 智能感知不显示评论

    如果我在 Visual Studio 2010 中输入类似的内容数据集1 我得到所有可用方法和属性的列表 智能感知 这很好用 但是 如果我在此列表中选择一个方法或属性 我不会得到 if 的描述 例如 如果我有类似的东西 public cla
  • 在 C++ 中什么时候首选传递指针而不是引用传递?

    我可以想象一种情况 其中输入参数可以为 NULL 以便首选传递指针而不是传递引用 有人可以添加更多案例吗 在传递的对象实际上将被修改的情况下 有些人更喜欢传递指针 当对象通过引用传递时 它们使用 pass by const referenc
  • 如何在c#中获取斐波那契数

    伙计们 我有一个关于斐波那契的问题 如何获得斐波那契数列 该数字也将以用户输入结束 例如 如果我输入 21 则输出必须为 0 1 1 2 3 5 8 13 21 这是我的代码 static void Main string args int

随机推荐

  • 计算一组的比例

    我正在尝试计算数据帧中组总数中每条记录的分数 我的数据如下 我有车站 月份和 PHylum 的因素 然后是总数 我想将总数显示为相对百分比 因此基本上是按车站和月份对总数进行求和 然后应用原始表格 在 R 中 我得到了 bn phyla g
  • Material UI - 更改焦点上文本字段的颜色

    我正在尝试更改文本字段中标签文本的颜色 但我似乎无法弄清楚 这是我正在尝试的
  • 如何在 tkinter 中显示 markdown 格式文本?

    In python 3 x with tkinterGUI 我开发了一个带有常规简单窗口的程序 我想展示一个markdown格式字符串保存在名为的字符串中markdownText在程序窗口上 markdownText italic or b
  • UISegmentedControl 颜色问题 - 颜色在模拟器上显示正常,但在设备上显示不正常

    FIXED 你不会相信它 这是一个 Winterboard 主题搞乱了它 混蛋 禁用主题瞧 效果完美 对于任何感兴趣的人来说 所讨论的主题是 Ayecorn 不酷 希望这对遇到同样问题的其他人有所帮助 抱歉各位 感谢您的所有投入 这里很棒的
  • 如何将复杂的 HTML 表单发布为 JSON?

    我的网页中有一个非常复杂的表单 用户实际上构建了一个复杂的对象 UI 使用 jQuery 进行处理 显示 隐藏部分 复制和删除子表单 尽管可能 但简单地在用户提交时发布表单似乎并不是最好的解决方案 为字段 可以有对象数组 创建唯一的名称并在
  • 将 UINavigationController 添加到现有的 UIViewController

    如何将现有的 UIViewController 使用presentModalViewController 呈现 添加到 UINavigationController 当用户点击按钮时 需要推送我的详细视图的新副本 换句话说 pushView
  • 计算数组属性的内存语义?

    这是一个允许用户标记事物的应用程序 标签只是字符串 一个数组TagHolder对象保存应用程序中使用的所有标签的列表 并用一个布尔值告诉是否选择了该标签 但这是一个实现细节 外部接口调用两个方法 selectedTags and setSe
  • 将属性和值从第 4 个父节点填充到 XML 文件的所有父节点

    我是 XSLT 新手 希望将相同的属性和值添加到从第二个父节点开始的所有父节点 这里的逻辑应该是 如果存在主节点 则属性 Mainattribute 应该是一次 并且对于主节点下的所有父节点的其余部分应该具有不同的属性 childattri
  • 创建二进制 PBM/PGM/PPM

    我试图了解如何创建二进制 PBM PGM PPM 文件 据我所知 每种格式有两种类型 普通格式和原始格式 例如 黑色 PBM 5x5 的结构如下所示 P1 This is a comment 5 5 1 1 1 1 1 1 1 1 1 1
  • Visual Studio 2015 如何禁用异常输出

    我正在制作一个带有更新和绘制的 C 应用程序 我发现更新确实很慢 尽管没有任何沉重的表达 在独立于 Visual Studio 启动我的应用程序后 我发现它的速度快了 100 倍 问题是 对于每个 try catch VStudio 都会在
  • 使用 asp:Button 将参数传递到函数中

    我正在尝试将参数传递给函数onClick of an asp Button
  • 从 Ada 代码构建静态库,无需 GNAT 即可链接

    我正在尝试从 Ada 代码创建一个静态库 该库可以与一些 C 代码链接 而无需使用 GNAT 工具进行最终链接 我的用例是 我正在尝试将一个用 Ada 编写的库交付给一个为嵌入式目标构建的 C 代码库 为目标构建最终二进制文件的工具链不包含
  • 从使用 List 的 .Net 调用 Java Web 服务

    我正在开发一个将由 Net 客户端使用的 Java Web 服务 该服务公开一个接受对象作为参数的方法 该对象有一个 List 类型的字段 Row 类也有一个 List 类型的字段 现在 当 Java 客户端使用此服务时 它会正确地将类型视
  • 是否可以在 React 中使用 Polymer?

    我一直在使用 React 并希望在 React 中使用 Polymer 标签 React 无法识别 Polymer 标签 因为 React 仅处理基本 DOM 标签 有没有办法将 Polymer 标签添加到 React DOM 库 对的 这
  • 有独立的Python类型转换库吗?

    是否有独立的类型转换库 我有一个仅理解字节 字符串的数据存储系统 但我可以标记元数据 例如要转换为的类型 我可以破解一些简单的类型转换器系统 就像我之前的所有其他应用程序所做的那样 或者我可以希望使用一个独立的库 除非我找不到一个 对于这样
  • 将 C# Stateful Service Fabric 应用程序从 Visual Studio 部署到 Linux

    编辑 04 06 18 gt 更新了问题的最新状态 因此 我有一个正在运行的 Net 4 6 Stateful Service 它当前在部署在 Azure 上的 Windows Service Fabric 集群上运行 从 09 2017
  • R(以前称为 Excel Solver)中预算分配的优化

    我将 Excel 中遇到的问题翻译成 R 我想以 Gesamt 由函数返回 最大化的形式分配固定预算 NrwGes lt function Budget Speed maxnrw cpcrp BudgetA lt Budget 1 Budg
  • 合并具有索引的数据帧,其中一个数据帧包含另一个数据帧(但不相同)

    例如 df1 具有形状 533 2176 指数如Elkford 5901003 DM 01010 df2 具有形状 743 12 指数如5901003 df1 索引括号中的数字将与 df2 的索引匹配 正如形状所示 一些索引根本不匹配 现在
  • Jquery修改每个循环中的元素

    使用jquery 我想循环具有 item 类的所有元素 并根据元素的索引应用不同的背景颜色 mapcolor 是颜色数组 长度 具有 item 类的元素数量 each item function i e e css background c
  • C# - 互斥锁的锁定问题

    我有一个 Web 应用程序 可以控制哪些 Web 应用程序从我们的负载均衡器获取服务流量 Web 应用程序在每个单独的服务器上运行 它在 ASP NET 应用程序状态的对象中跟踪每个应用程序的 输入或输出 状态 并且只要状态发生更改 该对象