ManualResetEvent - 事件积压

时间:2013-11-19 12:24:39

标签: c# multithreading events .net-4.0

我遇到了一些围绕ManualResetEvent和积压事件的问题。我的应用程序正在订阅消息,然后运行一项长任务。

我遇到的问题是我收到的消息多于我可以处理的消息。任务需要大约5秒才能处理,但我每2-3秒收到一条新消息。

理想情况下,我想要做的是忽略任何新事件,直到我完成处理任务然后再次开始'聆听'。目前,我似乎按照接收和处理的顺序对事件进行了积压。您可以想象,几个小时后,正在处理的消息非常陈旧。

我无法从多个线程运行长时间运行的任务。

也许我需要某种排队机制然后清除最后一条消息(Last On First Off)并删除队列?

有什么想法吗?

我还在长时间运行的过程结束时调用ManualResetEvent.Set() - 从我的研究中我明白这是正确的吗?我应该在长时间运行的任务开始时重置()以导致线程阻塞然后在结束时设置()?

2 个答案:

答案 0 :(得分:1)

创建一个循环缓冲区,将其视为LIFO队列(堆栈)。所以,假设您希望队列中最多有10个条目:

const int MaxItems = 10;
Item[] theQueue = new Item[];
int insertPoint = 0;
object myLock = new object();
// initialize the array to all NULL.

void Enqueue(Item t)
{
    lock (myLock)
    {
        theQueue[insertPoint] = t;
        insertPoint = (insertPoint+1) % 10;
    }
}

Item Dequeue()
{
    lock (myLock)
    {
        int takeFrom = insertPoint-1;
        if (takeFrom < 0)
            takeFrom = MaxItems-1;
        if (theQueue[takeFrom] != null)
        {
            var rslt = theQueue[takeFrom];
            insertPoint = takeFrom;
            return rslt;
        }
        // queue is empty. Either return null or throw an exception.
        return null;
    }
}

当然,你想把它们全部包装成一个漂亮的物体。但那是基本的想法。

答案 1 :(得分:0)

这个怎么样:

在任何给定时间,您都会处理一条消息,并等待处理一条消息。

收到新邮件时,会覆盖等待处理的邮件。

您的处理线程会等到有消息等待处理,然后将其标记为正在处理,处理它,然后重新开始。

添加一些同步逻辑,您将获得以下代码:

private object _sync = new object();
private Message _beingProcessed;
private Message _waitingToBeProcesssed;

public void OnMessageReceived(Message message)
{
    lock(sync)
    {
        _waitingToBeProcesssed = message;
        Monitor.Pulse(sync);
    }
}

public void DoWork()
{
    while (true)
    {
        lock (sync)
        {
            while (_waitingToBeProcesssed == null)
            {
                Monitor.Wait(sync);
            }

            _beingProcessed = _waitingToBeProcesssed;
            _waitingToBeProcesssed = null;
        }

        Process(_beingProcessed); //Do the actual work
    }
}