簡體   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