【发布时间】:2012-05-26 02:50:39
【问题描述】:
在以下代码中,TimerRecalcStatisticsElapsed 应该只运行一个实例。此回调调用的工作方法按顺序运行,with a maximum of one thread running at a time。
问题第 1 部分:
如果计时器的回调运行一个线程池线程 (as opposed to running the callback on a separate thread),那么说线程池可能会根据条件(达到 MaxThreads,线程池内部逻辑)排队并推迟线程以供以后执行是否正确?
问题第 2 部分:
假设一个计时器回调可以排队等待除立即执行之外的任何事情,这是否意味着任意数量的线程回调可以同时执行?
问题第 3 部分
假设第 2 部分为真,这是否意味着下面的代码可以同时运行多个回调?
我问的原因是因为有 几千个实例这个类在多 CPU 服务器上运行。我还看到与// Do Work Here 的乱序操作一致的数据损坏。
一边
// Do work here 在内部使用 System.Collections.Dictionary 并编辑 y 的值。它还为串行调用的后续函数删除了一些键。该函数缺少以前在第一次调用中存在的键 (x)。我认为这是因为最终语句obj.cleanupdata() 存在竞争条件
public class SystemTimerTest
{
readonly System.Timers.Timer timerRecalcStatistics;
readonly System.Diagnostics.Stopwatch stopwatchForRecalcStatistics = new System.Diagnostics.Stopwatch();
public SystemTimerTest(TimeSpan range, DataOverwriteAction action)
{
int recalculateStatisticsEveryXMillseconds = 1000;
timerRecalcStatistics = new System.Timers.Timer(recalculateStatisticsEveryXMillseconds);
timerRecalcStatistics.AutoReset = true;
timerRecalcStatistics.Elapsed += new System.Timers.ElapsedEventHandler(TimerRecalcStatisticsElapsed);
timerRecalcStatistics.Interval = recalculateStatisticsEveryXMillseconds;
timerRecalcStatistics.Enabled = true;
this.maxRange = range;
this.hashRunningTotalDB = new HashRunningTotalDB(action);
this.hashesByDate = new HashesByDate(action);
this.dataOverwriteAction = action;
}
private void TimerRecalcStatisticsElapsed(object source, System.Timers.ElapsedEventArgs e)
{
stopwatchForRecalcStatistics.Start();
Console.WriteLine("The TimerRecalcStatisticsElapsed event was raised at {0}", e.SignalTime.ToString("o"));
// DO WORK HERE
stopwatchForRecalcStatistics.Stop();
double timeBuffer = GetInterval(IntervalTypeEnum.NearestSecond, e.SignalTime) - stopwatchForRecalcStatistics.ElapsedMilliseconds;
if (timeBuffer > 0)
timerRecalcStatistics.Interval = timeBuffer;
else
timerRecalcStatistics.Interval = 1;
stopwatchForRecalcStatistics.Reset();
timerRecalcStatistics.Enabled = true;
}
}
【问题讨论】:
-
我认为问题在于 TimerRecalcStatisticsElapsed 方法的运行时间超过 1 秒,因此可能会同时执行多个实例。
-
@joocer 我希望通过将 Autoreset 设置为 false、运行任务并在事件完成后重新启用计时器来避免这种情况。这是一个好的解决方案,还是有更强大的解决方案?
标签: c# multithreading collections task-parallel-library interlocked