2009-07-07 3 views
45

У меня есть статический класс таймера, который будет вызываться ЛЮБОЙ веб-страницей, чтобы рассчитать, как долго каждая страница будет построена.Являются статическими методами потокобезопасными

Мой вопрос: Безопасны ли статические классы? В моем примере одновременные пользователи вызывают проблемы с моим временем начала и остановки? например, разные потоки, переписывающие значения начала и остановки.

Должен ли этот класс быть нестационарным классом?

(Этот класс вызывается из asp.net MasterPage.)

+7

MSDN: «Хотя экземпляр класса содержит отдельную копию всех полей экземпляра класса, есть только одна копия каждого статического поля». – colithium

ответ

56

Статические методы не являются по существу поточно-безопасный. С их помощью они не обрабатываются иначе, чем методы экземпляров. Разница заключается в том, что обычно следует попытаться сделать , сделав их поточно-безопасными. (Я не могу думать о каких-либо статических методах .NET BCL, которые не являются потокобезопасными.) Методы экземпляров часто не являются потокобезопасными, потому что типичный шаблон заключается в создании объекта и его повторном использовании из одного потока, и если он должен использоваться из нескольких потоков, при этом координация включает в себя обеспечение безопасного использования объекта. В очень многих случаях это более целесообразно делать в координирующем коде, чем в самом объекте. (Обычно вы хотите, чтобы целые последовательности операций были фактически атомарными - что-то, что невозможно сделать в объекте.)

Ваш класс Timer определенно не является потокобезопасным: две нити могут топать друг на друга с легкостью , и нет ничего, чтобы остановить поток от использования «устаревших» данных при расчете продолжительности.

Вместо этого используйте класс Stopwatch - вот для чего он предназначен. По общему признанию, если вы хотите использовать один экземпляр из нескольких потоков, вам нужно предпринять обычные шаги для обеспечения безопасности, но вы будете в гораздо лучшем положении в целом. По общему признанию, Stopwatch далек от совершенства - см. this question и комментарий ниже для более подробной информации - но это, по крайней мере, то, для чего предназначен тип. (Кто знает, это может быть исправлено некоторое время ...)

+4

Класс Stopwatch имеет свои проблемы, если вы используете его с несколькими ядрами или несколькими процессорами. Секундомер использует количество галочек для определения продолжительности времени, и из-за ошибки в BIOS секундомер может запускаться на одном ядре и останавливаться на другом, где количество отсчетов на двух ядрах не синхронизировано. Я обнаружил это в приложении с открытым исходным кодом Vss2Git, которое использовало секундомер и иногда пыталось дать отрицательную продолжительность времени. Fpr больше информации см. Http://stackoverflow.com/a/7919483/216440 –

+1

@SimonTewsi: Да, я слышал об этом раньше. Будет редактировать ссылку в ответ. –

4

Да, вы правы, статические члены/аксессоров этого класса заставит их быть перезаписаны другими пользователями.

Вот почему у вас есть экземпляры и нестатические элементы.

18

Ваш класс таймера определенно не является потокобезопасным. Вы должны создать нормальный класс и экземпляр его каждый раз, когда необходимо измерить время:

Timer timer = new Timer(); 

timer.Start(); 
//... 
timer.Stop(); 

decimal duration = timer.Duration(); 

еще лучше, есть встроенный класс .NET, который делает именно это:

Stopwatch sw = Stopwatch.StartNew(); 

sw.Stop(); 

TimeSpan duration = sw.Elapsed; 
20

Там является хорошим обсуждением here, в котором основное внимание уделяется механизмам и причинам, почему ваш пример не является потокобезопасным.

Чтобы суммировать, во-первых, ваши статические переменные будут совместно использоваться. Если вы можете сделать их локальными переменными, даже если они являются локальными для статического метода, они все равно получат свой собственный стек стека и, таким образом, будут потокобезопасными. Кроме того, если вы в противном случае защитите свои статические переменные (т. Е. Блокировки и/или другие многопоточные методы программирования, упомянутые другими в этом потоке), вы также можете сделать ваш образец статического класса потокобезопасным.

Во-вторых, поскольку ваш пример не принимает внешние экземпляры переменных, которые вы изменяете или на чье состояние может воздействовать другой поток, ваш пример также является потокобезопасным.

+0

Отличная информация, это именно то, что я пришел сюда, чтобы найти: если статический метод использует только локальные переменные, он поточно-безопасен? Приветствия. –

+4

Да. Но помните, что это должна быть переменная, локальная для метода, а не статическая переменная класса. (Я думаю, что иногда переменные класса называются локальными, но я могу ошибаться.) Поскольку вы сказали, что «использует только локальную переменную», я также предполагаю, что вы не назначаете ссылку пройденного параметр к локальной переменной. – Bill

Смежные вопросы