C# 如何最好地处置由于AutoResteEvent.WaitOne()而处于休眠状态的线程

C# 如何最好地处置由于AutoResteEvent.WaitOne()而处于休眠状态的线程,c#,multithreading,dispose,autoresetevent,waitone,C#,Multithreading,Dispose,Autoresetevent,Waitone,我有一个windows服务,它以5个线程之一发送电子邮件(这样做是为了提高服务发送电子邮件的速度): 大多数情况下,由于block.WaitOne的原因,线程处于休眠状态,因此上面的代码中止线程。但是,这会导致记录线程中止异常。我可以分别捕获线程中止异常和其他异常,并选择不记录,但它看起来不是很干净 清理这些线程而不导致过度日志记录的最佳方法是什么 更新: 我已将上述内容更改为: private ManualResetEvent block; private ThreadedQueue<M

我有一个windows服务,它以5个线程之一发送电子邮件(这样做是为了提高服务发送电子邮件的速度):

大多数情况下,由于
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;
}
专用手动复位事件块;
私有线程队列消息队列;
私有void DoSend()
{
尝试
{   
而(!this.disposing)
{
this.block.WaitOne();
Message=null;
if(!this.messageQueue.TryDequeue(out message)&&!this.disposing)
{                       
//现在没有其他东西可以发送来阻止发送线程
//除非我们正在处理,因为我们希望其他线程也退出
this.block.Reset();
}                   
如果(消息!=null)
{
这个。发送(消息);
}
}
}
捕获(例外情况除外)
{
//日志
}
}
公共空间处置()
{           
这是真的;
this.block.Set();
foreach(this.sendingThreads中的线程){
thread.Join();
}
this.block.Dispose();
this.sendingThreads=null;
}

谢谢你的帮助。

你在玩一个非常危险的游戏。您的代码特别容易死锁。您将看到线程状态为ThreadState.Running,并且线程在一微秒后调用WaitOne()。您的Join()调用将死锁并且永远不会返回


通过处理AutoResetEvent,可以使在WaitOne()调用中被阻止的线程解除阻止。这将抛出一个可预测的异常,ObjectDisposedException,一个您可以捕获的异常。使用另一个ManualResetEvent向螺纹发出退出信号。这样就不需要Thread.Abort()

改用BlockingCollection。它将产生简单简洁的代码,可以理解、管理和调试

一个生产者五个消费者。。。线程101


创建一个特殊的“死亡消息”,该消息会导致任何接收到它的线程终止。然后根据需要终止的线程数量对死亡消息进行排队…或者安排任何获得“死亡消息”的线程在终止之前重新对其进行排队。这将用一条消息杀死所有线程。观察良好。是的,这是可能的。我认为线程状态。如果需要删除,请运行。用你提出的解决方案;您是否建议我处理AutoResetEvent对象并捕获结果异常。为什么我需要另一个ManualResetEvent,一旦遇到ObjectDisposedException,上面的代码肯定会退出?调用block.Dispose()不会导致线程上的块被释放。它们仍处于休眠状态。仅处理ARE是不够的,线程可能未在其上阻塞。您需要一个额外的信号来让它看到它需要退出其处理循环。使用调试器查看它正在执行的操作。调试+窗口+线程。
if(thread.ThreadState == ThreadState.Running)
{
    thread.Join();
}
else if(thread.ThreadState == ThreadState.WaitSleepJoin)
{
    thread.Abort();
}
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;
}