SUMIT
SUMIT

Reputation: 38

How to determine no active child threads before closing application?

I am writing a program which is suppose to send emails to various email IDs [about 10000] at a time classified in a various categories.

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]);

    .....
    .....
}

After this, I should use .WaitAll as:

WaitHandle.WaitAll(waitHandles);

And, from the methods I am calling in different thread, I need to call .Set() Method and inform that the execution has finished. As..

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

But the problem is: I have Four different method which I call on separate threads each, and in each method there are another new threads, my code is like:

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 may contains up to 10000 Rows.)

So, I am not getting the point how to use

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

For the solution to this problem I have find a temporary code:

WaitHandle.WaitAll(waitHandles);

[REPLACED WITH]

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

But as we know

Thread.Sleep();

wastes CPU time, I need a better solution. I have found many solution on Google but they are not exactly what I need.

EDIT: I am using SMTP to send emails.

Upvotes: 0

Views: 59

Answers (1)

Yuval Itzchakov
Yuval Itzchakov

Reputation: 149528

Sending an e-mail over the wire is an IO operation. Such as, we can take advantage of using async API's offered by SmtpClient. This way, we have no need to generate any threads which will simply block until the request finishes.

To do this, we'll use 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);
}

This method uses the async-await and the Task Asynchronous Pattern. This way, you don't execute any redundant threadpool threads, and you gain the benefit of async IO. You can get started here.

Upvotes: 1

Related Questions