【问题标题】:asp.net prevent multiple processesasp.net 防止多个进程
【发布时间】:2017-03-09 13:29:16
【问题描述】:

我的 ASP.NET 站点中有不能由 2 个线程或进程同时运行的代码,因此我将其锁定。假设只有一个进程,这是可行的,并且由于 IIS 中的“最大工作进程”设置为 1,我觉得这是合理的。然而,我做了一个让我想知道的实验:

我创建了这个动作:

public void Test()
{
    for (int i = 0; i < 100; i++)
    {
        System.IO.File.AppendAllText(@"c:\tmp\d.txt", $"a: {i}\n");
        System.Threading.Thread.Sleep(1000);
    }
}

并从我的浏览器中调用它。然后我将a: 切换到b:,编译它,然后从另一个浏览器选项卡中调用它。然后我打开d.txt,看到的是这样的:

b: 31
a: 67
b: 32
a: 68
b: 33
a: 69

显然有2个进程同时运行,我的锁会不够用。确保我的一段代码不会同时运行的最佳方法是什么?

【问题讨论】:

  • 使用写锁打开文件,写入打开的流,完成后处理关闭文件的流(只需将整个内容包装在 using 块中)。如果文件已经打开,如何处理遇到初始异常的其他线程尚不清楚,这取决于您的逻辑。您不能使用锁甚至互斥锁,这些在网络场架构中都不是线程安全的,因此如果您希望您的站点在多个 Web 服务器之间实现负载平衡,那么这种方法(锁或互斥锁)将无法正常工作。
  • @Igor 我的代码没有打开任何文件。这只是为了证明2个进程可以同时运行的一个测试动作。
  • my code does not open any files System.IO.File.AppendAllText 会做什么?
  • @wezten 好的。如果你真的需要帮助解释你在做什么,并给我们一些实际示例代码
  • 你没看第二句吗?请在回复之前阅读整个评论。 ... If there are multiple entry points on the same server use a named mutex.

标签: c# asp.net


【解决方案1】:

听起来您真的在寻找队列或类似队列的单例服务。使用常规的 ASP.NET WebAPI 不会让 OOB 变得那么容易。你可以摆弄让它工作,但我会考虑以下之一:

  1. 使用端点连接到的实际队列(MSMQ、Azure 服务总线队列、Rabbit MQ 等),并在该队列上执行实际工作的侦听器。这可能无法真正为您提供所需的同步通信,但可以确保让事情保持有序和单一。
  2. 创建一个 WCF 服务并用InstanceContextMode = InstanceContextMode.SingleConcurrencyMode = ConcurrencyMode.Single 装饰它。 WCF 框架将负责为您提供作为单例的工作。您可以将其托管在 Windows 服务而不是 IIS 中,这将进一步确保多个进程不存在,并且您可以完全控制线程模型。

【讨论】:

    【解决方案2】:

    如果你在这里有一种方法是使用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();
    
            // now call your file manipulation function
            Test();
        }
        finally
        {
            // Release the Mutex.
            mut.ReleaseMutex();
        }   
    

    【讨论】:

    • 即使重新启动 IIS 并且线程中止,互斥锁是否会被释放?
    • @wezten 当您按下重新启动 IIS 或更改某些文件并且项目将需要重新编译时,您在池中设置了一些时间,IIS 等待您的应用程序完成它们的工作- 否则就是杀了它。如果您需要某种这种同步 - 您可以使用 global.asax 来触发和停止互斥锁内部的工作并且需要很长时间 - 在任何情况下互斥锁都会释放。
    • @wezten 默认情况下,您必须知道会话使用互斥锁并锁定您的呼叫 - 看看那个答案:stackoverflow.com/questions/11629600/…
    【解决方案3】:

    您描述的问题可能是由线程或进程引起的。

    假设你只想在一台机器上解决这个问题,并且你想阻止多个工作进程(如标题所示),那么你可能只是在工作进程的生命周期内锁定一个文件。

    例如。在 Application_Start 中,您可以获得临时目录 (System.IO.Path.GetTempPath),然后使用 IApplicationHost 中的站点名称等通用标识符准备文件名。然后用排他锁(或死)锁定文件。我建议在杀死你的工作进程之前在 windows 应用程序中添加一些东西。

    如果/当您的工作进程死亡时,文件应该被解锁。您甚至可以使用 CreateFile 和 FILE_FLAG_DELETE_ON_CLOSE 让它自行删除。

    当然,如果您的应用程序可能托管在多台服务器上,那么您可能不想使用这种方法,因为这还不够。

    【讨论】:

      猜你喜欢
      • 2011-02-27
      • 1970-01-01
      • 1970-01-01
      • 2012-03-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多