Для чего небезопасно?

Есть много статей и обсуждений, объясняющих, почему хорошо создавать потокобезопасные классы. Говорят, что если доступ к нескольким потокам, например, поле в то же время, могут быть только некоторые плохие последствия. Итак, в чем смысл сохранения non потокобезопасного кода? Я сосредоточен в основном на .NET, но я считаю, что основные причины не зависят от языка.

например. Статические поля .NET не являются потокобезопасными. Каков был бы результат, если бы они были потокобезопасными по умолчанию? (без необходимости выполнять "ручную" блокировку). Каковы преимущества использования (по сути, невыполнения обязательств) безопасности, не связанной с потоком?

Одна вещь, которая приходит мне на ум - это производительность (скорее всего, это предположение). Это довольно интуитивно, что, когда функция или поле не нуждается в потокобезопасности, этого не должно быть. Однако вопрос: зачем? Является ли безопасность потоков просто дополнительным количеством кода, который вам всегда нужно реализовать? В каких сценариях я могу быть на 100% уверенным, что, например, поле не будет использоваться сразу двумя потоками?

Ответы

Ответ 1

Написание потокобезопасного кода:

  • Требуется более опытных разработчиков.
  • Сложнее и потребляет больше усилий по кодированию.
  • Сложнее тестировать и отлаживать
  • Обычно имеет большую производительность

Но! Код, защищенный от ошибок, не всегда необходим. Если вы можете быть уверены, что какой-то фрагмент кода будет доступен только по одному потоку, список, указанный выше, станет огромным и лишним накладными расходами. Это как аренда фургона при поездке в соседний город, когда вас двое и мало багажа.

Ответ 2

Безопасность потоков поставляется с затратами - вам нужно блокировать поля, которые могут вызвать проблемы при одновременном доступе.

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

Ответ 3

Итак, в чем смысл сохранения небезопасного кода?

Стоимость. Как вы и предполагали, обычно наблюдается штраф в исполнении.

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

Ответ 4

Безопасность потоков не является предложением "да" или "нет". Значение "безопасности потоков" зависит от контекста; означает ли это "одновременное чтение в безопасном режиме, одновременная запись небезопасно"? Означает ли это, что приложение просто может вернуть устаревшие данные вместо сбоев? Есть много вещей, которые это может означать.

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

Ответ 5

Записывать потокобезопасный код время от времени трудно. Например, простая ленивая загрузка требует двух проверок для "== null" и блокировки. Это действительно легко повредить.

[EDIT]

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

Ответ 6

Бывают ситуации, когда "поточно-безопасный" не имеет смысла. Это соображение в дополнение к более высоким навыкам разработчика и увеличению времени (разработка, тестирование и время выполнения все принимают хиты).

Например, List<T> является обычно используемым классом, не связанным с потоком. Если бы мы создали безопасный поток, как бы реализовать GetEnumerator? Подсказка: нет хорошего решения.

Ответ 7

Итак, в чем смысл сохранения небезопасного кода?

Предоставляя код, который не является потокобезопасным, вы оставляете его до программиста , чтобы решить, какой именно уровень изоляции.

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

Рико Мариани написал две статьи под заголовком "" Установка вашей синхронизации на правильном уровне" и Поместив вашу синхронизацию на правильный уровень - решение, у которого есть хороший пример этого в действии.

В статье у него есть метод под названием DoWork(). В нем он вызывает другие классы Read дважды Write дважды, а затем LogToSteam.

Read, Write и LogToSteam все разделили блокировку и были потокобезопасными. Это хорошо, за исключением того факта, что поскольку DoWork также был потокобезопасным, вся работа синхронизации в каждом Read, Write и LogToSteam была пустой тратой времени.

Все это связано с природой императивного программирования. Его побочные эффекты вызывают необходимость в этом.

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

Ответ 8

Поверните этот вопрос на голову.

В первые дни программирования не было никакого кода Thread-Safe, потому что не было понятия потоков. Началась программа, затем продолжалась шаг за шагом до конца. Мероприятия? Что это? Потоки? А?

По мере того как аппаратное обеспечение стало более мощным, концепции того, какие типы проблем могут быть решены с помощью программного обеспечения, стали более изобретательными, а разработчики стали более амбициозными, инфраструктура программного обеспечения стала более сложной. Это также стало намного более тяжелым. И здесь мы сегодня, со сложной, мощной, а в некоторых случаях и без излишней сверхпрочной экосистемой программного обеспечения, которая включает потоки и "безопасность потоков".

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

Ответ 9

So, what is the point of keeping non thread-safe code?

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

Возвращаясь к реальности, программист good пробует свой уровень лучше иметь секционную блокировку, а не блокировку всего контекста. Примером может быть блокировка нескольких строк кода за раз в разных процедурах, чем блокирование всего в функции.

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

например. рассмотрим функцию foobar(), которая получает новые данные для каждого вызова и использует switch() case для типа данных для изменения a node в дереве. Блокировка может быть в основном устранена (если не полностью). В каждом случае оператор коснется другого node в дереве. Это может быть более конкретный пример, но я думаю, что он уточняет мою мысль.