我有一个正在运行的服务不断处理数据,它接收通过消息传递来处理新数据的请求。在忙于处理新的请求时,将它们合并在一起,以便一次处理它们。 AutoResetEvent用于通知处理器有新的请求可用。使用AutoResetEvent发送工作线程信号
我的问题是在EventLoop中,是否有可能在WaitOne之后的currentRequest为null?
在lock(_eventLocker)之外是否存在_eventAvailable.Set()方法是不好的做法?我把它移出来,这样它就不会在WaitOne上开始并立即竞争锁定(_eventLocker)。
关于如何更好地编写下面的代码的任何建议?
public sealed class RealtimeRunner : MarshalByRefObject
{
/// <summary>
/// The actual event, new events get merged into this if it is not null
/// </summary>
private Request _pendingRequest;
/// <summary>
/// Used to signal the runner thread when an event is available to process
/// </summary>
private readonly AutoResetEvent _eventAvailable = new AutoResetEvent(false);
private readonly object _eventLocker = new object();
/// <summary>
/// Called on a background thread via messaging
/// </summary>
public void QueueEvent(RealtimeProcessorMessage newRequest)
{
bool mergedRequest;
lock (_eventLocker)
{
if (_pendingRequest == null)
{
mergedRequest = false;
_pendingRequest = new Request(newRequest, _engine);
}
else
{
mergedRequest = true;
_pendingRequest.Merge(newRequest, _engine);
}
}
_eventAvailable.Set();
}
/// <summary>
/// This is running on its own thread
/// </summary>
private void EventLoop()
{
while (true)
{
// Block until something exists in _pendingRequest
_eventAvailable.WaitOne();
Request currentRequest;
lock (_eventLocker)
{
currentRequest = _pendingRequest;
_pendingRequest = null;
}
// CAN THIS EVER BE NULL?
if (currentRequest == null)
continue;
//do stuff with the currentRequest here
}
}
}
谢谢,我看着生产者的消费者,但由于我可以合并多个请求到一个单一的请求,我想要一个更手动的方法。在我的服务中,处理可能需要30秒,并且请求可能会每秒多次出现。我想我可以循环并使用TryTake将它们合并到消费者一方?那么会有一个m_Queue.Take()调用后面跟着一段时间(m_Queue.TryTake())吗? – BrandonAGr 2011-05-06 16:35:45
@BrandonAGr:绝对。在调用'Take'获得初始请求后,您可以立即调用另一个调用'TryTake'的循环来快速选择几个请求。你在这里有很多可能性。但是,当队列为空时,您仍然需要调用'Take'来产生阻塞效应。 – 2011-05-06 16:41:00