如何在关闭应用程序之前确定没有活动的子线程

本文关键字:活动 线程 应用程序 | 更新日期: 2023-09-27 18:35:33

我正在编写一个程序,该程序应该一次向各种电子邮件ID(大约10000个)发送电子邮件,并分类为各种类别。

static void Main(string[] args)
{
    WaitHandle[] waitHandles = new WaitHandle[]
    {
        new AutoResetEvent(false),
        new AutoResetEvent(false),
        new AutoResetEvent(false),
        new AutoResetEvent(false)
    };
    ThreadPool.QueueUserWorkItem(new WaitCallback(p.SendMailToCart), waitHandles[0]);
    ThreadPool.QueueUserWorkItem(new WaitCallback(p.SendScheduled), waitHandles[1]);
    ThreadPool.QueueUserWorkItem(new WaitCallback(p.Mailer), waitHandles[2]);
    ThreadPool.QueueUserWorkItem(new WaitCallback(p.BookReviewMail), waitHandles[3]);
    .....
    .....
}

在此之后,我应该使用 .等待全部作为:

WaitHandle.WaitAll(waitHandles);

而且,从我在不同的线程中调用的方法来看,我需要调用 .Set() 方法并通知执行已完成。如。。

AutoResetEvent waitHandle = (AutoResetEvent) obj;
waitHandle.Set();

但问题是:我有四个不同的方法,每个方法都在单独的线程上调用,每个方法中都有另一个新线程,我的代码是这样的:

foreach(DataRow dr in dtEmails.Rows)
{
    Thread sendMail = new Thread(delegate()
    {
        string _emailBody = CreateEmails.CreateEmail();
        if (_emailBody.Length > 0)
        {
            bool result = SendEmail.SendMail(SubjectLine(_subjectline), userID, _emailBody);
            if (result == true)
            {
                Console.WriteLine("> Email sent to {0}", userID);
            }
            else
            {
                Console.WriteLine("> Email sending failed for {0}.", userID);
            }
        }
    });
    sendMail.Start();
    sendMail.IsBackground = true;
}

dtEmail(数据表最多可以包含 10000 行。

所以,我不明白如何使用

AutoResetEvent waitHandle = (AutoResetEvent) obj;
waitHandle.Set();

为了解决这个问题,我找到了一个临时代码:

WaitHandle.WaitAll(waitHandles);

[替换为]

while (true)
{
    if (ThreadCounter() <= 1)
    {
        Thread.Sleep(1000 * 30);
        Environment.Exit(1);
    }
    Thread.Sleep(1000 * 30);
}

但正如我们所知

Thread.Sleep();

浪费CPU时间,我需要更好的解决方案。我在谷歌上找到了很多解决方案,但它们并不是我所需要的。

编辑:我正在使用SMTP发送电子邮件。

如何在关闭应用程序之前确定没有活动的子线程

通过网络发送电子邮件是一种 IO 操作。例如,我们可以利用SmtpClient提供的异步 API 。这样,我们就不需要生成任何线程,这些线程只会阻塞,直到请求完成。

为此,我们将使用 SmtpClient.SendMailAsync

public async Task SendMailsAsync()
{
     DataTable dt = new DataTable();
     var mailTasks = dt.Rows.OfType<DataRow>().Select(mail => 
     {
        var smtpClient = new SmtpClient();
        return smtpClient.SendMailAsync(new MailMessage(from, to, subject, body));
     }).ToArray();
     await Task.WhenAll(mailTasks);
}

此方法使用async-await和任务异步模式。这样,您就不会执行任何冗余线程池线程,并获得异步 IO 的好处。你可以从这里开始。