繁体   English   中英

ASP.NET中的全局变量

[英]Global variable in ASP.NET

我希望阻止一个线程进入代码,而另一个线程仍在执行那段代码:

我目前正在进行以下操作: global.asax.cs

    private static bool _isProcessingNewIllustrationRequest;

    public static bool IsProcessingNewIllustrationRequest
    {
        get { return _isProcessingNewIllustrationRequest; }
        set { _isProcessingNewIllustrationRequest = value; }
    }

然后在MVC中:

    public ActionResult CreateNewApplication()
    {
        if (!Global.IsProcessingNewIllustrationRequest)
        {
            Global.IsProcessingNewIllustrationRequest = true;

            // DO WORK... RUN CODE
            Global.IsProcessingNewIllustrationRequest = false;
            return View("Index", model);
        }
        else
        {
            // DISPLAY A MESSAGE THAT ANOTHER REQUEST IS IN PROCESS
        }
    }

但如果好像代码不起作用,因为两个线程(Chrome和Firefox)仍然同时执行代码。

更新

private Object thisLock = new Object();     
public ActionResult CreateApplication()
        {
            ILog log = LogManager.GetLogger(typeof(Global));
            string aa = this.ControllerContext.HttpContext.Session.SessionID;
            log.Info("MY THREAD: " + aa);

            lock (thisLock)
            {
                Thread.Sleep(8000);

                DO SOME STUFF

            }
        }

即使使用日志,线程2(Firefox会话)仍会进入代码,而session1(Chrome)使用锁执行它。 我错过了什么?

我可以看到两个明显的原因,为什么这段代码不会做你想要的。

问题#1:它不是线程安全的。 每当有人连接到您的服务器时,该请求将在一个线程中运行,如果有多个请求进入,那么多个线程都将同时运行。 几个线程可以同时读取标志,所有人都看到它是错误的,所以所有人都进入他们的if块并且所有人都做了他们的工作,这正是你想要阻止的。

这是一种“竞争条件”(结果取决于谁赢得比赛)。 布尔变量不足以解决竞争条件。

有很多方法可以解决这个问题。 最好的方法是删除共享状态,这样每个线程都可以完全独立于其他线程运行,并且不需要锁定其他线程。 但我会假设你已经考虑过这个并且它不实用。 接下来要看的是互斥监视器 监视器使用起来有点简单,但只有当两个线程实际上位于同一个appdomain和相同的进程中时,它们才有效。 这让我...

问题2:两个线程可能不在同一个进程中。 最新版本的IIS将启动多个单独的工作进程来处理Web请求。 每个进程都有自己的地址空间,这意味着每一个进程(在技术上每个过程中的每个应用程序域)都有自己的“全局”变量的副本!

事实上,如果您正在构建一个真正高流量的Web站点,则不同的工作进程甚至可能无法在同一台计算机上运行

工人流程是你最可能的罪魁祸首。 如果您遇到竞争条件,问题将非常罕见(当它出现时,甚至更难以调试)。 如果你每次都看到它,我的钱就是多个工人流程。

让我们假设所有工作进程都在同一台服务器上(毕竟,如果你有那种需要可以扩展到多个Web服务器的应用程序的预算,你就会比我更了解多线程编程)。 如果所有内容都在同一台服务器上,您可以使用命名的互斥锁来协调不同的应用程序域和进程。 像这样的东西:

public static Mutex _myMutex = new Mutex(false, @"Global\SomeUniqueName");

public ActionResult CreateNewApplication()
{
    if (_myMutex.WaitOne(TimeSpan.Zero))
    {
        // DO WORK... RUN CODE
        _myMutex.ReleaseMutex();
        return View("Index", model);
    }
    else
    {
        // DISPLAY A MESSAGE THAT ANOTHER REQUEST IS IN PROCESS
    }
}

如果另一个线程拥有互斥锁, WaitOne(TimeSpan.Zero)将立即返回。 如果您希望其他线程通常能够快速完成,您可以选择传递非零时间跨度; 那么它会在放弃之前等待很长时间,这会给用户提供比立即失败的“请稍后再试”错误消息更好的体验。

ASP.NET根据需要调整工作进程,不要对抗它。

使用数据库队列并让ASP.NET以最佳方式工作。 在创建高度无法维护的代码的基础上,如果可以的话,你会扼杀服务器试图控制线程。 如果你确实找到了控制它的方法,我无法想象你将要遇到的错误类型。

在上面的Edit案例中,您正在使用每个控制器实例创建该新对象,因此它只会锁定将在同一个线程上的代码 - 并且只有一个请求,因此不执行任何操作。

尝试在应用程序启动时记录您的全局类变量,以便运行静态初始化程序,并且您知道事情是“设置”。 然后使用存在于此全局类中的对象(它可以是任何东西 - 一个字符串)并将其用作锁变量。

实现此目的的唯一方法是使用互斥锁。 “锁定”语句是互斥锁的语法糖。

您应该将代码抽象为具有静态成员变量的静态类,以便app-domain中的所有线程都可以访问此类。

现在,您可以在锁定语句中将所有代码封装在两个静态成员函数中。 请确保您在两个成员函数中锁定相同的锁变量。

此外,如果您不希望这些成员函数是静态的,那么您的类不必是静态的。 只要您的锁变量是静态的,您就可以了。

希望这可以帮助。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM