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

时间:2011-05-13 08:48:09

标签: c# .net timer synchronization waithandle

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

这些操作绑定到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。

谢谢!

3 个答案:

答案 0 :(得分:1)

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

答案 1 :(得分:1)

也许你可以使用双线程队列/批量执行? 请注意,代码向下只是我在没有visual studio的情况下写的一个概念,所以我在列表中做,最好用Queue完成,但我不记得没有intellisense的语法:) ... < / p>

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);
    }

答案 2 :(得分:0)

使用Reactive Extensions (Rx)你可能会为自己省去很多麻烦 - 它有很多很棒的方法可以按照你要求的方式撰写活动。

This site是一种方便的方式来查看rx可以做的事情。