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

时间:2014-12-28 15:36:45

标签: c# multithreading

我正在编写一个程序,假设在各种类别的时间发送电子邮件到各种电子邮件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]);

    .....
    .....
}

在此之后,我应该使用.WaitAll:

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;
}

dtEmails(DataTable最多可包含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时间,我需要一个更好的解决方案。 我在Google上找到了很多解决方案,但它们并不是我所需要的。

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

1 个答案:

答案 0 :(得分:1)

通过线路发送电子邮件是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的好处。 您可以开始使用here