Безопасность потоков System.Timers.Timer vs System.Threading.Timer

В этой статье: http://msdn.microsoft.com/en-us/magazine/cc164015.aspx автор заявляет, что System.Threading.Timer не является потокобезопасным.

С тех пор это повторялось в блогах, в книге Рихтера "CLR через С#", на SO, но это никогда не оправдано.

Кроме того, документация MSDN гарантирует, что "этот тип является потокобезопасным".

1) Кто говорит правду?

2) Если это оригинальная статья, что делает System.Threading.Timer небезопасным и как его обертка System.Timers.Timer обеспечивает большую безопасность потоков

Спасибо

Ответ 1

Нет, это не так, как это работает. Асинхронные классы таймера .NET отлично потокобезопасны. Проблема с безопасностью потоков заключается в том, что она не является транзитивным свойством, она не делает другой код, который также выполнял потокобезопасность. Код, который вы написали, а не программист .NET Framework.

Это та же самая проблема с очень распространенным предположением, что код пользовательского интерфейса Windows в корне небезопасен. Это не так, код внутри Windows отлично потокобезопасен. Проблема - это весь код, который работает, который не является частью Windows, а не написан программистом Microsoft. Всегда есть такой код, вызванный вызовом SendMessage(). Какая программа выполняет собственный код, который написал программист. Или код, который он не писал, как крючок, установленный какой-то утилитой. Код, предполагающий, что программа не затрудняет работу и просто выполняет обработчики сообщений в одном потоке. Обычно он это делает, не делая этого, покупает у него много неприятностей.

Такая же проблема с событием System.Timers.Timer.Elapsed и обратным вызовом System.Threading.Timer. Программисты совершают много ошибок, записывая этот код. Он работает асинхронно в произвольном потоке threadpool, прикосновение к любой общей переменной действительно требует блокировки для защиты состояния. Очень легко упускать из виду. И что еще хуже, намного хуже, очень легко попасть в кучу проблем, когда код снова запустится, прежде чем предыдущий вызов прекратил работу. Запускается, когда интервал таймера слишком низкий или слишком загружена машина. Теперь есть два потока, выполняющих один и тот же код, что редко приходит к хорошему концу.

Речь идет сложно, новости в одиннадцать.