2013-04-08 2 views
5

В заявлении SmtpClient Class указано, что члены экземпляра не являются потокобезопасными. Это можно увидеть, если одновременные вызовы сделаны в Send или SendAsync. Оба метода будут вызывать InvalidOperationException во втором вызове, если первый еще не завершен.Являются ли методы SmtpClient.SendMailAsync Thread Safe?

Метод SendMailAsync, представленный в .NET 4.5, не отображает InvalidOperationException как исключение. Используют ли новые методы .NET 4.5 какие-то очереди? Отражатель не может пролить свет на детали реализации этого класса, поэтому я предполагаю, что это было реализовано в собственных методах.

Может ли несколько потоков безопасно обращаться к методу SendMessageAsync на общем экземпляре клиента SMTP?

+1

Способы, которые не являются потокобезопасными, не должны вызывать исключение, если вы обращаетесь к ним из нескольких потоков. – svick

ответ

10

Я не уверен, почему использование рефлектора не сработало для вас. Если я декомпилировать, я вижу следующий код:

[HostProtection(SecurityAction.LinkDemand, ExternalThreading=true)] 
public Task SendMailAsync(MailMessage message) 
{ 
    TaskCompletionSource<object> tcs = new TaskCompletionSource<object>(); 
    SendCompletedEventHandler handler = null; 
    handler = delegate (object sender, AsyncCompletedEventArgs e) { 
     this.HandleCompletion(tcs, e, handler); 
    }; 
    this.SendCompleted += handler; 
    try 
    { 
     this.SendAsync(message, tcs); 
    } 
    catch 
    { 
     this.SendCompleted -= handler; 
     throw; 
    } 
    return tcs.Task; 
} 

Как вы можете видеть, это простой TAP обертка для SendAsync(). И если SendAsync() выбрасывает исключение, SendMailAsync() просто реверсирует его.

Итак, вывод заключается в том, что SendMailAsync() не является потокобезопасным и что его исключения недополнены.

+0

Я предполагаю, что я застрял, реализуя свой собственный механизм очередей. Спасибо за ответ. – brianfeucht

+0

@brianfeucht Почему бы вам не использовать несколько экземпляров 'SmtpClient' вместо (по одному для каждого потока)? – svick

+0

Таков план. Создайте пул SmtpClients, чтобы я мог контролировать, сколько соединений создается машиной. Если клиент доступен, он будет доступен. Если пул полностью используется, запрос будет поставлен в очередь для следующего доступного клиента. – brianfeucht

2

В качестве примечания (поскольку у меня недостаточно комментариев для комментариев), традиционным способом записи асинхронной операции было использование модели асинхронного программирования (APM), но сегодня мы обычно используем Асинхронный шаблон на основе задач (TAP) с его ключевыми словами async/wait. И хотя нет ничего необычного в том, что TAP-обертки вокруг APM-методов, также можно увидеть APM-обертки вокруг методов TAP.