我正在开发一个模拟网络的应用程序,该网络包含许多交换消息的节点。我尝试使用Queue模拟传输通道,其中每个节点都可以发送消息。然后,另一个实体接管消息并将其传递到指定节点。然后,我希望在消息队列空闲一段时间(例如X)时发信号通知(带有事件)传输阶段的结束,即没有新的消息添加到队列中为X毫秒。
据我所知,我的案例遵循消费者/制作人范例。到目前为止,我已经完成了以下工作:
public class Com<T>
{
private Thread dispatcher;
private Queue<T> queue;
private int waitTime;
private Object locker;
private Timer timer;
public event EventHandler EmptyQueueEvent;
public Com()
{
queue = new Queue<T>();
locker = new Object();
waitTime = X;
timer = new Timer(FireEmpty, null, Timeout.Infinite,Timeout.Infinite);
dispatcher = new Thread(Serve);
dispatcher.IsBackground = true;
dispatcher.Start();
}
private void Serve()
{
while (true)
{
try
{
if (queue.Count == 0)
{
timer.Change(waitTime, 0);
Thread.Sleep(Timeout.Infinite);
}
}
catch (ThreadInterruptedException)
{
}
while (queue.Count != 0)
{
lock (locker)
{
deliver(queue.Dequeue());
}
}
}
}
private void deliver(T item)
{
// Do stuff
}
public void Add(T item)
{
timer.Change(Timeout.Infinite, Timeout.Infinite);
lock (locker)
{
queue.Enqueue(item);
}
dispatcher.Interrupt();
}
private void FireEmpty(object o)
{
//Fire Event
}
}
然而,运行我的模拟证明我的同步是不够的,因为我有时在尝试使我的消息出队时得到“ThreadInterruptedException”(在方法Serve()中)。请注意,每次运行模拟时都不会发生异常,而是很少发生:大约每850-1000次执行(我正在迭代地执行执行)..
有人知道我的代码有什么问题吗? :)
答案 0 :(得分:1)
在尝试获取Queue
计数之前,您是否尝试过锁定?像:
private void Serve()
{
while (true)
{
try
{
int count = 0;
lock(locker)
count= queue.Count;
if (count == 0)
{
timer.Change(waitTime, 0);
Thread.Sleep(Timeout.Infinite);
}
}
catch (ThreadInterruptedException)
{
}
while (queue.Count != 0)
{
lock (locker)
{
deliver(queue.Dequeue());
}
}
}
}
在您尝试计算项目数量的同时,可能会调用添加项。此外,如果您使用.net 4.0,则可能需要考虑System.Collections.Concurrent
中的一个集合。
** 更新 **
我只是仔细看看你的代码,并有一个“哦呃”的时刻。您应该收到ThreadInterruptException
,因为您正在呼叫delegate.Interrupt()
。检查MSDN documentation。我认为你需要做的就是使用类似ManualResetEvent
的内容,而不是在Interrupt()
上调用WaitOne()
。
** UPDATE2 ** 这里有一些示例代码,包括我的其他锁定建议(在Gist上): https://gist.github.com/1683547