使用等待句柄的条件定期计时器

本文关键字:计时器 条件 等待 句柄 | 更新日期: 2023-09-27 17:56:14

我需要一个计时器等效项,它将定期执行一些特定的操作(例如,更新数据库中的某些进度或检查要在数据库中执行的新作业)。

这些操作绑定到 WaitHandle,该 WaitHandle 指定是否需要执行作业。因此,基本上这可能是,例如,当数据库中有新实体并触发对这些新实体的搜索时,从外部设置的AutoResetEvent。计时器是必需的,因为我想限制对数据库的查询数。因此,如果收到 10 个新通知,则只会设置一次 AutomaticResetEvent,并且所有这些通知也只有一个查询。

我的第一次尝试看起来像这样:

class ConditionalScheduler
{
    public void AddConditionalAction(WaitHandle handle, Action action)
    {
        lock (syncRoot)
        {
            handles.Add(handle);
            actions.Add(handle, action);
        }
    }
    private readonly object syncRoot = new object();
    private readonly Dictionary<WaitHandle, Action> actions = new Dictionary<WaitHandle, Action>();
    private readonly List<WaitHandle> handles = new List<WaitHandle>();
    public void RunTimerLoop()
    {
        do
        {
            WaitHandle[] waitHandles = handles.ToArray();
            int index = WaitHandle.WaitAny(waitHandles);
            if (index >= 0)
            {
                WaitHandle handle = waitHandles[index];
                Action action;
                lock (syncRoot)
                {
                    action = actions[handle];
                }
                action();
            }
            Thread.Sleep(5000);
        } while (true);
    }

这种方法的问题在于,WaitHandle.WaitAny 只会给我触发的第一个 WaitHandle 的索引。因此,如果我有 2 个或更多触发的 WaitHandles,那么我只会执行第一个操作,而不会执行其他操作。

您是否有更好的设计来实现在指定时间段内触发的所有操作所需的结果?如果它简化了问题,我可以使用另一种通知机制而不是 WaitHandles。

谢谢!

使用等待句柄的条件定期计时器

也许你可以使用双线程队列/批量执行?请注意,代码下来只是我在没有 Visual Studio 的情况下编写的一个概念,所以我正在列表上做,这最好用队列来完成,但我不记得没有智能感的语法:)......

private readonly Dictionary<WaitHandle, Action> actions = new Dictionary<WaitHandle, Action>();
    private readonly List<WaitHandle> handles = new List<WaitHandle>();
    private readonly List<WaitHandle> triggeredHandles = new List<WaitHandle>();
// thread 1
    public void CheckLoop()
    {
        do
        {
            WaitHandle[] waitHandles = handles.ToArray();
            int index = WaitHandle.WaitAny(waitHandles);
            if (index >= 0)
            {
                lock (triggeredHandles)
                {
                   triggeredHandles.Add(waitHandles[index]);
                }
            }            
        } while (true);
    }
// thread 2
public void RunLoop()
    {
        do
        {
            lock(triggeredHandles)
            {
                foreach (var th in triggeredHandles) {
                   Action action;
                   lock (syncRoot)
                   {
                       action = actions[th];
                   }
                   action();                   
                }
                triggeredHandles.Clear();
            }
            Thread.Sleep(5000);
        } while (true);
    }

您是否考虑过使用内置的计时器类? System.Threading.Timer 是一个轻量级的实现,它使用 ThreadPoolSystem.Timers.Timer 提供相关事件和更多功能。

通过使用反应式扩展(Rx),您可能会省去很多麻烦 - 它有很多很好的方法可以按照您请求的方式编写事件。

这个网站是查看 rx 可以做的事情的便捷方式。