1

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

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

谢谢!

4

3 回答 3

1

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

于 2011-05-13T08:56:51.897 回答
1

也许您可以使用两个线程队列/批量执行?请注意,下面的代码只是我在没有 Visual Studio 的情况下编写的一个概念,所以我在一个列表中进行操作,最好使用 Queue 来完成,但我不记得没有智能感知的语法 :) ...

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);
    }
于 2011-05-13T09:06:02.293 回答
0

使用Reactive Extensions (Rx),您可能会省去很多麻烦——它有很多很棒的方法可以按照您要求的方式编写事件。

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

于 2011-05-13T08:52:19.227 回答