【发布时间】:2013-02-05 09:50:56
【问题描述】:
我有一个 Windows 服务,它以 5 个线程之一发送电子邮件(这样做是为了提高服务发送电子邮件的速度):
private AutoResetEvent block;
private ThreadedQueue<Message> messageQueue;
private void DoSend()
{
try
{
while(!this.disposing)
{
this.block.WaitOne();
Message message = null;
if (this.messageQueue.TryDequeue(out message))
{
this.block.Set();
}
if(message != null)
{
this.Send(message);
}
}
}
catch(Exception ex)
{
// Log
}
}
我有一个Queue 方法,该方法将一条或多条新消息添加到 messageQueue 并调用 block.Set() 以便 5 个线程之一可以发送消息。当允许其中一个线程运行时,只要队列中有消息,就会调用block.Set(),以便下一条消息可以出队,并且5个线程中的另一个可以发送它。以此类推,直到队列为空。这一切正常。
但是,当我处理我的对象时,我设置了处理变量,然后为每个线程设置:
if(thread.ThreadState == ThreadState.Running)
{
thread.Join();
}
else if(thread.ThreadState == ThreadState.WaitSleepJoin)
{
thread.Abort();
}
大多数时候,线程由于block.WaitOne 而处于休眠状态,因此上面的代码中止了线程。但是,这会导致记录线程中止异常。我可以将线程中止异常与其他异常分开捕获并选择不记录,但这似乎不是很干净。
在不导致过多日志记录的情况下清理这些线程的最佳方法是什么?
更新:
我已将以上内容更改为:
private ManualResetEvent block;
private ThreadedQueue<Message> messageQueue;
private void DoSend()
{
try
{
while(!this.disposing)
{
this.block.WaitOne();
Message message = null;
if (!this.messageQueue.TryDequeue(out message) && !this.disposing)
{
// There's nothing else to send for now to block the sending threads
// unless we're disposing as we want the other threads to exit too
this.block.Reset();
}
if(message != null)
{
this.Send(message);
}
}
}
catch(Exception ex)
{
// Log
}
}
public void Dispose()
{
this.disposing = true;
this.block.Set();
foreach(Thread thread in this.sendingThreads) {
thread.Join();
}
this.block.Dispose();
this.sendingThreads = null;
}
感谢您的帮助。
【问题讨论】:
-
创建一个特殊的“死亡消息”,导致任何接收它的线程终止。然后排队尽可能多的死亡消息,因为你有需要终止的线程。
-
..或安排任何获得“死亡消息”的线程在终止之前重新排队。这将通过一条消息杀死所有线程。
标签: c# multithreading dispose autoresetevent waitone