简体   繁体   English

ASP.NET中的全局变量

[英]Global variable in ASP.NET

I wish to stop a thread from entering code while another thread is still executing that bit of code: 我希望阻止一个线程进入代码,而另一个线程仍在执行那段代码:

I'm currently going the following: global.asax.cs 我目前正在进行以下操作: global.asax.cs

    private static bool _isProcessingNewIllustrationRequest;

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

Then in MVC: 然后在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
        }
    }

But if seems as if the code isn't working, because both threads(Chrome & Firefox) still executes the code at the same time. 但如果好像代码不起作用,因为两个线程(Chrome和Firefox)仍然同时执行代码。

UPDATED 更新

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

            }
        }

Even with the log, thread 2 (Firefox session) still goes into the code while session1 (Chrome) is executing it with the lock. 即使使用日志,线程2(Firefox会话)仍会进入代码,而session1(Chrome)使用锁执行它。 What am I missing? 我错过了什么?

I can see two obvious reasons why this code won't do what you want. 我可以看到两个明显的原因,为什么这段代码不会做你想要的。

Problem #1: It's not threadsafe. 问题#1:它不是线程安全的。 Every time someone connects to your server, that request is going to run in a thread, and if multiple requests come in, then multiple threads are all going to be running at the same time. 每当有人连接到您的服务器时,该请求将在一个线程中运行,如果有多个请求进入,那么多个线程都将同时运行。 Several threads could very well read the flag at the same time, all see that it's false, and so all enter their if block and all do their work, which is exactly what you're trying to prevent. 几个线程可以同时读取标志,所有人都看到它是错误的,所以所有人都进入他们的if块并且所有人都做了他们的工作,这正是你想要阻止的。

This is a "race condition" (the results depend on who wins the race). 这是一种“竞争条件”(结果取决于谁赢得比赛)。 Boolean variables aren't enough to solve a race condition. 布尔变量不足以解决竞争条件。

There are a bunch of ways to actually fix this problem. 有很多方法可以解决这个问题。 The best would be to remove the shared state, so each thread can run completely independently of the others and there's no need to lock the others out; 最好的方法是删除共享状态,这样每个线程都可以完全独立于其他线程运行,并且不需要锁定其他线程。 but I'll assume you've already considered that and it's not practical. 但我会假设你已经考虑过这个并且它不实用。 The next things to look at are mutexes and monitors . 接下来要看的是互斥监视器 Monitors are a little simpler to use, but they only work if both threads are actually in the same appdomain and the same process. 监视器使用起来有点简单,但只有当两个线程实际上位于同一个appdomain和相同的进程中时,它们才有效。 That brings me to... 这让我...

Problem #2: The two threads might not be in the same process. 问题2:两个线程可能不在同一个进程中。 Recent versions of IIS will launch multiple separate worker processes to handle Web requests. 最新版本的IIS将启动多个单独的工作进程来处理Web请求。 Each process has its own address space, meaning each process (technically each appdomain within each process) has its own copy of your "global" variable! 每个进程都有自己的地址空间,这意味着每一个进程(在技术上每个过程中的每个应用程序域)都有自己的“全局”变量的副本!

In fact, if you're building a really high-traffic Web site, the different worker processes may not even run on the same computer. 事实上,如果您正在构建一个真正高流量的Web站点,则不同的工作进程甚至可能无法在同一台计算机上运行

Worker processes are your most likely culprit. 工人流程是你最可能的罪魁祸首。 If you were facing a race condition, the problem would be incredibly rare (and even more incredibly hard to debug when it did come up). 如果您遇到竞争条件,问题将非常罕见(当它出现时,甚至更难以调试)。 If you're seeing it every time, my money is on multiple worker processes. 如果你每次都看到它,我的钱就是多个工人流程。

Let's assume that all the worker processes will be on the same server (after all, if you had the kind of budget that required apps that can scale out to multiple Web servers, you would already know way more about multithreaded programming than I do). 让我们假设所有工作进程都在同一台服务器上(毕竟,如果你有那种需要可以扩展到多个Web服务器的应用程序的预算,你就会比我更了解多线程编程)。 If everything's on the same server, you can use a named Mutex to coordinate across different appdomains and processes. 如果所有内容都在同一台服务器上,您可以使用命名的互斥锁来协调不同的应用程序域和进程。 Something like this: 像这样的东西:

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

The WaitOne(TimeSpan.Zero) will return immediately if another thread owns the mutex. 如果另一个线程拥有互斥锁, WaitOne(TimeSpan.Zero)将立即返回。 You could choose to pass a nonzero timespan if you expect that the other thread will usually finish quickly; 如果您希望其他线程通常能够快速完成,您可以选择传递非零时间跨度; then it will wait that long before giving up, which would give the user a better experience than failing instantly into a "please try again later" error message. 那么它会在放弃之前等待很长时间,这会给用户提供比立即失败的“请稍后再试”错误消息更好的体验。

ASP.NET spools up worker processes as needed, don't fight it. ASP.NET根据需要调整工作进程,不要对抗它。

Use a database queue and let ASP.NET work optimally. 使用数据库队列并让ASP.NET以最佳方式工作。 You will be choking the sever trying to control the threading, if you even can, on top of creating highly un-maintainable code. 在创建高度无法维护的代码的基础上,如果可以的话,你会扼杀服务器试图控制线程。 If you do find a way to control it, I can't imagine the type of bugs you are going to run into. 如果你确实找到了控制它的方法,我无法想象你将要遇到的错误类型。

In your Edit case above, you are creating that new object with every controller instance so its only going to lock code that would be on that same thread - and theres only one request so that does nothing. 在上面的Edit案例中,您正在使用每个控制器实例创建该新对象,因此它只会锁定将在同一个线程上的代码 - 并且只有一个请求,因此不执行任何操作。

Try to log your global class variables upon application startup so the static initializers run and you know things are 'setup'. 尝试在应用程序启动时记录您的全局类变量,以便运行静态初始化程序,并且您知道事情是“设置”。 Then use an object that exists in this global class (it could be anything - a string) and use that as your lock variable. 然后使用存在于此全局类中的对象(它可以是任何东西 - 一个字符串)并将其用作锁变量。

The only way to accomplish this is by using a mutex. 实现此目的的唯一方法是使用互斥锁。 The "lock" statement is syntactic sugar for a mutex. “锁定”语句是互斥锁的语法糖。

You should abstract your code into a static class that has a static member variable so all threads in your app-domain will have access to this class. 您应该将代码抽象为具有静态成员变量的静态类,以便app-domain中的所有线程都可以访问此类。

Now, you can encapsulate all the code in your two static member functions in a lock statement. 现在,您可以在锁定语句中将所有代码封装在两个静态成员函数中。 Please ensure that you are locking the same lock variable in the two member functions. 请确保您在两个成员函数中锁定相同的锁变量。

Also, if you do not want these member functions to be static then your class doesn't have to be static. 此外,如果您不希望这些成员函数是静态的,那么您的类不必是静态的。 You will be fine as long as your lock variable is static. 只要您的锁变量是静态的,您就可以了。

Hope this helps. 希望这可以帮助。

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

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