C #: Что делать, если статический метод вызывается из нескольких потоков?

95

В моем приложении у меня есть статический метод, который вызывается из нескольких потоков одновременно. Есть ли опасность перепутать мои данные?

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

TalkingCode
источник

Ответы:

99

Переменные, объявленные внутри методов (за возможным исключением « захваченных » переменных), изолированы, поэтому вы не получите никаких внутренних проблем; однако, если ваш статический метод обращается к какому-либо общему состоянию, все ставки отключены.

Примеры общего состояния:

  • статические поля
  • объекты, к которым осуществляется доступ из общего кеша (несериализованные)
  • данные, полученные с помощью входных параметров (и состояние этих объектов), если возможно, что несколько потоков касаются одного и того же объекта (ов)

Если у вас общее состояние, вы должны либо:

  • позаботьтесь о том, чтобы состояние не изменялось после того, как оно может быть опубликовано (лучше: используйте неизменяемые объекты для представления состояния и сделайте снимок состояния в локальную переменную, то есть вместо whatever.SomeDataповторной ссылки вы читаете whatever.SomeData один раз в локальную переменную, а затем просто используйте переменную - обратите внимание, что это помогает только для неизменяемого состояния!)
  • синхронизировать доступ к данным (все потоки должны синхронизироваться) - либо взаимно исключающие, либо (более детализированные) читатель / писатель
Марк Гравелл
источник
1
@Diego - этот комментарий предназначен для меня или для @Holli?
Марк Грейвелл
Холли, просто чтобы добавить к вашему ответу некоторую практическую информацию.
Диего Перейра,
1
@Marc Я не могу полностью согласиться с "Переменные, объявленные внутри методов (за возможным исключением" захваченных "переменных), изолированы". Рассмотрим дескриптор файла, объявленный в статическом методе. Тогда один поток может получить доступ к дескриптору, когда его использует другой поток. Это приведет к неожиданному поведению. Или ваша "захваченная" переменная тоже означает "дескриптор файла".
прабхакаран 01
9
@prabhakaran, если дескриптор файла является переменной метода, он ограничен только этим вызывающим. Любой другой вызывающий абонент будет разговаривать с другой переменной (переменные метода зависят от каждого вызова). Теперь доступ к базовому файлу - это отдельная проблема, но она не связана с C # или .NET. Если дескриптор не является общим, можно было бы ожидать какой-то мьютекс / блокировку, если этот сценарий вероятен.
Марк Грейвелл
29

Да это просто удача. ;)

Не имеет значения, является ли метод статическим или нет, важно, являются ли данные статическими или нет.

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

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

Гуффа
источник
7
Очень понравилась эта линия - It doesn't matter if the method is static or not, what matters is if the data is static or not. Чтобы добавить, локальные переменные, объявленные в рамках статического метода, не образуют ту часть данных, о которой нам нужно беспокоиться в данном сценарии.
RBT
отличный ответ. Очень помогли.
Fractal
15

Статические методы должны подходить для нескольких потоков.

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

Дуг Фергюсон
источник
2
Ключевое слово здесь - синхронизация :-)
Г. Стойнев
2
одновременное чтение нормально, но одновременное чтение И запись приведет к неожиданному поведению
Freestyle076
10

MSDN всегда говорит:

Любые общедоступные статические (общие в Visual Basic) члены этого типа являются потокобезопасными. Потокобезопасность любых членов экземпляра не гарантируется.

Изменить: как говорят здесь ребята, это не всегда так, и, очевидно, это относится к классам, разработанным таким образом в BCL, а не к пользовательским классам, где это не применяется.

Маркот
источник
3
Уф! Наконец, я понял значение этой заметки, которая так часто встречается в документации MSDN. Таким образом, когда MS разрабатывает статический метод (где публикуется эта заметка) в BCL, они не обращаются к какой-либо переменной / члену / состоянию, которые выходят за рамки этого метода. Они полностью полагаются на локальные переменные в области видимости метода только для реализации логики этого метода. Очень рад, что вы поделились.
RBT
@Marcote, разве не наоборот? Члены экземпляра безопасны, потому что по одному на каждый экземпляр. Однако статические члены не являются потокобезопасными, потому что они используются всеми экземплярами этого класса? quora.com/…
Fractal
1
это зависит. Я бы никогда не стал относиться к члену экземпляра как к безопасному по умолчанию. Вот почему целый набор библиотек и во избежание повреждения данных среди прочего.
Марко
1
хорошо, спасибо @Marcote. Я постепенно понимаю, что мне нужно многому научиться.
Fractal