gpt4 book ai didi

c# - 线程池会不会排队一个定时器的回调函数,有时会同时调度多个线程?

转载 作者:行者123 更新时间:2023-11-30 20:05:47 25 4
gpt4 key购买 nike

在下面的代码中,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;
}
}

最佳答案

ad 1) ThreadPool 是否可以延迟回调方法的执行并不重要,因为无论如何回调都不能保证在另一个计时器间隔结束之前完成执行(例如,线程可以被线程调度程序挂起,或者回调可能调用长时间运行的函数)。

广告 2) 这是 MSDN 对 Timer 的描述类:

If the SynchronizingObject property is null, the Elapsed event is raised on a ThreadPool thread. If processing of the Elapsed event lasts longer than Interval, the event might be raised again on another ThreadPool thread. In this situation, the event handler should be reentrant.

所以答案是肯定的,回调可以在多个线程上同时执行。

广告 3) 是的。并且您应该避免在回调方法中使用共享资源(timerRecalcStatistics、stopwatchForRecalcStatistics),或者同步对这些共享资源的访问(例如使用锁),或者将适当的对象设置为 Timer 的 SynchronizingObject属性,或将 Timer 的 AutoReset 属性设置为 false(并在定时器回调结束时再次启用定时器)。

更新:我认为 Jon Skeet 的 answer不能解决你的问题。另外实现你自己的 SynchonizingObject 恕我直言比必要的更复杂(但在不知道整个问题的情况下很难说)。我希望这个实现应该有效(但我没有测试它):

public class MySynchronizeInvoke : ISynchronizeInvoke
{
private object SyncObject = new Object();
private delegate object InvokeDelegate(Delegate method, object[] args);

public IAsyncResult BeginInvoke(Delegate method, object[] args)
{
ElapsedEventHandler handler = (ElapsedEventHandler)method;
InvokeDelegate D = Invoke;
return D.BeginInvoke(handler, args, CallbackMethod, null);
}

private void CallbackMethod(IAsyncResult ar)
{
AsyncResult result = ar as AsyncResult;
if(result != null)
((InvokeDelegate)result.AsyncDelegate).EndInvoke(ar);
}

public object EndInvoke(IAsyncResult result)
{
result.AsyncWaitHandle.WaitOne();
return null;
}

public object Invoke(Delegate method, object[] args)
{
lock(SyncObject)
{
ElapsedEventHandler handler = (ElapsedEventHandler)method;
handler(args[0], (ElapsedEventArgs)args[1]);
return null;
}
}

public bool InvokeRequired
{
get { return true; }
}
}

关于c# - 线程池会不会排队一个定时器的回调函数,有时会同时调度多个线程?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10654163/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com