C #: Що робити, якщо статичний метод викликається з декількох потоків?


93

У моєму додатку у мене є статичний метод, який викликається з декількох потоків одночасно. Чи існує небезпека змішування моїх даних?

З першої спроби метод не був статичним, і я створював кілька екземплярів класу. У цьому випадку мої дані якось переплуталися. Я не впевнений, як це відбувається, бо це трапляється лише іноді. Я все ще налагоджую. Але зараз метод статичний, у мене поки що проблем немає. Можливо, це просто удача. Я точно не знаю.


Відповіді:


96

Змінні, оголошені всередині методів (за винятком можливих " захоплених " змінних), ізольовані, тому ви не отримаєте жодних притаманних проблем; однак, якщо ваш статичний метод отримує доступ до будь-якого спільного стану, всі ставки вимкнені.

Прикладами спільного стану можуть бути:

  • статичні поля
  • об'єкти, доступ до яких здійснюється із загального кешу (несеріалізовані)
  • дані, отримані через вхідні параметри (і стан на ці об'єкти), якщо можливо, що кілька потоків торкаються одного і того ж об'єкта

Якщо у вас спільний стан, ви повинні:

  • будьте обережні, щоб не мутувати стан, коли він може бути спільним (краще: використовуйте незмінні об'єкти, щоб представляти стан, і зробіть знімок стану в локальну змінну - тобто замість whatever.SomeDataповторного посилання ви читаєте whatever.SomeData один раз у локальну змінну, а потім просто використовуйте змінну - зауважте, що це допомагає лише для незмінного стану!)
  • синхронізувати доступ до даних (усі потоки повинні синхронізуватися) - або взаємовиключні, або (більш детальний) зчитувач / запис

1
@Diego - цей коментар призначений для мене чи для @Holli?
Марк Гравелл

Холлі, просто щоб додати практичну інформацію до Вашої відповіді.
Дієго Перейра,

1
@Marc Я не можу повністю погодитися з "Змінні, оголошені всередині методів (за винятком" захоплених "змінних), ізольовані". Розглянемо дескриптор файлу, який оголошено статичним методом. Тоді одна нитка може отримати доступ до дескриптора, коли інша нитка використовує її. Це призведе до несподіваної поведінки. Або ваша "захоплена" змінна також означає "обробник файлу".
прабхакаран,

9
@prabhakaran, якщо дескриптор файлу є змінною методу, він застосовується лише до цього абонента. Будь-який інший абонент буде розмовляти з іншою змінною (змінні методу - за викликом). Тепер доступ до базового файлу є окремою проблемою, але це не пов’язано з c # або .NET. Якщо дескриптор не є спільним, можна очікувати певного типу mutex / lock, якщо такий сценарій є ймовірним.
Марк Гравелл

29

Так, це просто удача. ;)

Не має значення статичність методу чи ні, важливо те, статичні дані чи ні.

Якщо кожен потік має свій окремий екземпляр класу зі своїм власним набором даних, немає ризику змішування даних. Якщо дані статичні, існує лише один набір даних, і всі потоки мають однакові дані, тому неможливо їх не змішати.

Коли ваші дані в окремих екземплярах все одно змішуються, це, швидше за все, тому, що дані насправді не є окремими.


7
Полюбив цей рядок - It doesn't matter if the method is static or not, what matters is if the data is static or not. Додамо лише, що локальні змінні, оголошені в межах статичного методу, не утворюють тієї частини даних, про яку нам потрібно турбуватися в даному сценарії.
RBT

чудова відповідь. Дуже допомогли.
Фрактал

15

Статичні методи повинні бути точними для декількох потоків.

Статичні дані, з іншого боку, можуть спричинити проблему, оскільки намагання отримати доступ до одних і тих самих даних з різних потоків потрібно контролювати, щоб одночасно лише один потік читав або записував дані.



2
читання одночасно відбувається, але одночасне читання та письмо призведе до несподіваної поведінки
Freestyle076

9

MSDN Завжди каже:

Усі загальнодоступні статичні (спільно використовуються у Visual Basic) члени цього типу є потокобезпечними. Будь-які члени екземпляра не гарантовано захищають від потоків.

Редагувати: Як кажуть тут хлопці, це не завжди так, і, очевидно, це стосується класів, розроблених таким чином у BCL, а не класів, створених користувачем, де це не стосується.


3
Фу! Нарешті, я зрозумів значення цієї примітки, яка так часто зустрічається в документації MSDN. Отже, в основному, коли MS розробляє статичний метод (де ця примітка опублікована) у BCL, вони не отримують доступу до жодної змінної / члена / стану, що виходить за рамки цього методу. Вони повністю покладаються на локальні змінні, орієнтовані на метод, лише для реалізації логіки цього методу. Дуже рада, що ви поділилися.
RBT

@Marcote, чи не навпаки правда? Члени екземпляра в безпеці, оскільки на екземплярі є один. Однак статичні члени не є безпечними для потоків, оскільки вони спільно використовуються між усіма екземплярами цього класу? quora.com/…
Фрактал

1
це залежить. Я б ніколи не поводився з членом екземпляра в безпеці за замовчуванням. Ось чому цілий набір бібліотек та, щоб уникнути пошкодження даних серед іншого.
Маркот

1
добре, дякую @Marcote. Я повільно з’ясовую, що мені є чому вчитися.
Фрактал
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.