我希望在另一个线程仍在执行那段代码时阻止一个线程输入代码:
我目前正在进行以下操作: 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 session )仍然进入代码,而 session 1(Chrome)正在使用锁执行它。我错过了什么?
最佳答案
我可以看出为什么这段代码不能按您的要求执行的两个明显原因。
问题 #1:它不是线程安全的。每次有人连接到您的服务器时,该请求将在一个线程中运行,如果有多个请求进入,那么多个线程将同时运行。多个线程可以很好地同时读取该标志,所有线程都看到它是假的,因此所有线程都进入他们的 if
block 并完成他们的工作,这正是你试图阻止的。
这是一个“竞争条件”(结果取决于谁赢得了比赛)。 bool 变量不足以解决竞争条件。
有很多方法可以实际解决这个问题。最好的办法是删除共享状态,这样每个线程都可以完全独立于其他线程运行,而无需将其他线程锁定在外;但我假设您已经考虑过这一点,但这是不切实际的。接下来要看的是mutexes和 monitors .监视器使用起来稍微简单一些,但它们只有在两个线程实际上都在同一个应用程序域和同一个进程中时才起作用。这让我想到...
问题 #2:两个线程可能不在同一个进程中。 IIS 的最新版本将启动多个独立的工作进程来处理 Web 请求。每个进程都有自己的地址空间,这意味着每个进程(从技术上讲,每个进程中的每个应用程序域 )都有自己的“全局”变量副本!
事实上,如果您正在构建一个非常高流量的网站,不同的工作进程甚至可能不会在同一台计算机上运行。
工作进程最有可能是罪魁祸首。如果您面临竞争条件,问题将非常罕见(而且当它出现时更难以调试)。如果您每次都看到它,我的钱花在了多个工作进程上。
让我们假设所有工作进程都在同一台服务器上(毕竟,如果您的预算需要能够扩展到多个 Web 服务器的应用程序,那么您对多线程编程的了解比我多得多做)。如果一切都在同一台服务器上,您可以使用一个名为 Mutex 的服务器。跨不同的应用程序域和进程进行协调。像这样:
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)
将立即返回。如果您希望其他线程通常会很快完成,则可以选择传递一个非零时间跨度;然后它会在放弃之前等待那么久,这会给用户带来比立即失败并显示“请稍后再试”错误消息更好的体验。
关于c# - ASP.NET 中的全局变量,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7563825/