Reputation: 38
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
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