- c - 在位数组中找到第一个零
- linux - Unix 显示有关匹配两种模式之一的文件的信息
- 正则表达式替换多个文件
- linux - 隐藏来自 xtrace 的命令
我有一个 Windows 服务,每 5 秒检查一次工作。它使用 System.Threading.Timer
来处理检查和处理,并使用 Monitor.TryEnter
来确保只有一个线程正在检查工作。
假设它必须是这种方式,因为以下代码是服务创建的其他 8 个 worker 的一部分,每个 worker 都有自己需要检查的特定工作类型。
readonly object _workCheckLocker = new object();
public Timer PollingTimer { get; private set; }
void InitializeTimer()
{
if (PollingTimer == null)
PollingTimer = new Timer(PollingTimerCallback, null, 0, 5000);
else
PollingTimer.Change(0, 5000);
Details.TimerIsRunning = true;
}
void PollingTimerCallback(object state)
{
if (!Details.StillGettingWork)
{
if (Monitor.TryEnter(_workCheckLocker, 500))
{
try
{
CheckForWork();
}
catch (Exception ex)
{
Log.Error(EnvironmentName + " -- CheckForWork failed. " + ex);
}
finally
{
Monitor.Exit(_workCheckLocker);
Details.StillGettingWork = false;
}
}
}
else
{
Log.Standard("Continuing to get work.");
}
}
void CheckForWork()
{
Details.StillGettingWork = true;
//Hit web server to grab work.
//Log Processing
//Process Work
}
问题来了:
上面的代码允许 2 个定时器线程进入 CheckForWork()
方法。老实说,我不明白这是怎么可能的,但我在运行该软件的多个客户端上都遇到过这种情况。
我今天推送一些工作时得到的日志显示它检查了两次工作,我有 2 个线程独立尝试处理,这一直导致工作失败。
Processing 0-3978DF84-EB3E-47F4-8E78-E41E3BD0880E.xml for Update Request. - at 09/14 10:15:501255801
Stopping environments for Update request - at 09/14 10:15:501255801
Processing 0-3978DF84-EB3E-47F4-8E78-E41E3BD0880E.xml for Update Request. - at 09/14 10:15:501255801
Unloaded AppDomain - at 09/14 10:15:10:15:501255801
Stopping environments for Update request - at 09/14 10:15:501255801
AppDomain is already unloaded - at 09/14 10:15:501255801
=== Starting Update Process === - at 09/14 10:15:513756009
Downloading File X - at 09/14 10:15:525631183
Downloading File Y - at 09/14 10:15:525631183
=== Starting Update Process === - at 09/14 10:15:525787359
Downloading File X - at 09/14 10:15:525787359
Downloading File Y - at 09/14 10:15:525787359
日志是异步写入并排队的,所以不要深入挖掘时间完全匹配的事实,我只是想指出我在日志中看到的显示我有 2 个线程的内容点击一段我认为永远不应该被允许的代码。 (虽然日志和时间是真实的,只是经过清理的消息)
最终发生的事情是 2 个线程开始下载一个足够大的文件,其中一个线程最终拒绝访问该文件并导致整个更新失败。
上面的代码怎么能允许这样做呢?去年我遇到了这个问题,当时我有一个 lock
而不是 Monitor
并假设这只是因为计时器最终开始获得足够的偏移量由于 lock
阻止了我正在堆叠计时器线程,即一个阻塞了 5 秒并在 Timer 触发另一个回调时通过了正确的时间,并且它们都以某种方式进入了它。这就是我使用 Monitor.TryEnter 的原因
选项,这样我就不会一直堆叠计时器线程。
有什么线索吗?在我之前尝试解决此问题的所有情况下,System.Threading.Timer
一直是一个常数,我认为这是根本原因,但我不明白为什么。
最佳答案
我可以在日志中看到您提供了一个 AppDomain
重新启动,对吗?如果是,您确定在 AppDomain
重新启动期间您有一个且唯一的服务对象吗?我认为在此期间并非所有线程都同时停止,其中一些线程可以继续轮询工作队列,因此不同 AppDomain
中的两个不同线程得到相同的 Id
工作。
您可能可以通过使用 static
关键字标记您的 _workCheckLocker
来解决此问题,如下所示:
static object _workCheckLocker;
并通过初始化该字段为您的类引入静态构造函数(如果是内联初始化,您可能会遇到一些更复杂的问题),但我不确定这是否足以满足您的情况 - 在 期间AppDomain
重启静态类也会重新加载。据我了解,这不适合您。
也许您可以为您的工作人员引入 static
字典而不是对象,这样您就可以检查正在处理的文档的 Id
。
另一种方法是为您的服务处理Stopping
事件,这可能会在AppDomain
重启期间调用,您将在其中引入CancellationToken
。 ,并在这种情况下使用它来停止所有工作。
此外,正如@fernando.reyes 所说,您可以为同步引入称为互斥锁的重锁结构,但这会降低您的性能。
关于c# - Monitor.TryEnter 和 Threading.Timer 竞争条件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39515192/
我想知道 Monitor 类。据我所知,所有等待线程都不是 FIFO。第一个获得锁的并不总是等待队列中的第一个。这样对吗?有什么方法可以确保 FIFO 条件? 问候 最佳答案 如果您指的是内置方式,则
我们在 vb.net 应用程序的一部分中使用并行扩展从字典(字符串、数据表)中检索数据表。在检索表的方法中,我们使用 Monitor.TryEnter。有时,我们会收到错误消息“从未同步的代码块调用了
我正在努力让事情变得更简单。这是我的代码: If Threading.Monitor.TryEnter(syncRoot) Then Try 'do s
我尝试搜索此内容,但没有找到最适合我所面临问题的建议。 我的问题是我们有可用资源(计算引擎)的列表/堆栈。这些资源用于执行某些计算。 执行计算的请求是由外部进程触发的。所以当请求计算时,我需要检查是否
我的部分代码隐藏: object _sync = new object(); private async void OnKeyDown(object sender, KeyEventArgs e) {
我有一种情况,为了测试,我只希望我的计时器方法 (FooMethod) 一次运行一个。在下面的示例中,FooMethod 作为委托(delegate)传递给计时器。此类有许多具体实例。我认为通过将 _
在 TCriticalSection 上调用 TryEnter 方法时,结果始终为 true。当然,只有在能够获取锁的情况下才应该返回 true 吗? var MyCritSect: TCriti
考虑以下实现仅对一个线程的非阻塞访问的函数。 public bool TryCancelGroup() { if (Monitor.TryEnter(_locked)) {
我正在尝试保护一些多线程代码,并且正在添加单元测试以证明我已经修复了我们之前看到的损坏。 虽然我在这样做时遇到了一些意想不到的行为。为什么下面的代码在the docs时会成功表明 TryEnter 应
如果在 java 中某些线程拥有此方法,如何跳过方法,我知道在 .net 中存在 Monitor.TryEnter,我可以通过这样的事情来完成: if(Monitor.TryEnter()){ //
我正在查看已创建的代码,它在一个方法调用中使用 TryEnter 并在其他方法调用中锁定。所以,像这样: private readonly object xmppLock = new object()
我在代码审查期间被建议去做 bool acquiredLock = false; try { Monitor.TryEnter(lockObject, 500, ref acquiredLoc
是否可以检测是否是同一个线程试图释放锁?我们在代码中有很多地方看起来像: try { try { if(!Monitor.TryEnter(obj, 2000))
我有一个 Windows 服务,每 5 秒检查一次工作。它使用 System.Threading.Timer 来处理检查和处理,并使用 Monitor.TryEnter 来确保只有一个线程正在检查工作
结果 锁定:85.3 微秒 Monitor.TryEnter:11.0 微秒 锁不是展开成同样的代码吗? 编辑:1000 次迭代的结果:锁定:103.3 微秒Monitor.TryEnter:20.2
我正在使用 Threading.Timer 在我的应用程序中运行消息泵。 有时所需的工作比计时器间隔之间的间隔更长,我需要代码然后被“跳过”。 我写了一个小测试应用程序来测试,并在锁定时一直遇到 Sy
这里的问题是:如果获取对象独占锁的线程(例如通过使用 Monitor.Enter)终止,是否会神奇地释放该对象的独占锁?如果那是真的,那么假设我们从另一个线程调用 Monitor.Exit - 因为我
我想我遗漏了一些关于 Monitor.Enter 和 Monitor.TryEnter 正确行为的信息。这是我编写的一段代码,用于将问题与其余代码分开: object lockObj = new ob
我是一名优秀的程序员,十分优秀!