|
Заблокирован
|
|
Потокобезопасность переменной18.10.2020, 12:03. Показов 5732. Ответов 28
Метки нет (Все метки)
Правильно ли я понимаю, что стандартным способом обеспечения потокобезопасности переменной является использование методов класса Interlocked (который делает ряд операций с переменной атомарными)?
Есть ли другие способы? Например, можно ли обеспечить потокобезопасность свойства, защитив одним ключевым словом lock код и геттера и сеттера свойства?
0
|
|
| 18.10.2020, 12:03 | |
|
Ответы с готовыми решениями:
28
Потокобезопасность в C#
Потокобезопасность uint |
|
Модератор
|
|||||||
| 18.10.2020, 13:45 | |||||||
lock - это оператор (инструкция). Операторы могут применяться только внутри методов.Подобного модификатора насколько знаю нет. Один из простых вариантов обеспечить потокозащищённость свойства:
1
|
|||||||
|
Заблокирован
|
|
| 18.10.2020, 13:58 [ТС] | |
|
Элд Хасп,
а зачем модификатор readonly у формального поля _myPropertyLock? P.S. Кстати, почему всегда во всех примерах эти формальные поля никак больше не используются в коде? Нельзя ли для блокировки использовать не формальное, а реальное поле или свойство?
0
|
|
|
Модератор
|
||
| 18.10.2020, 14:09 | ||
|
Так как в методе, после получения из переменной ссылки на объект, контроля за состоянием переменной обеспечить нельзя, то может возникнуть ситуация когда между lock в разных потоках, значение этой переменой будет изменено. И блокировка будет происходить по разным объектам. Что приведёт к отсутствию взаимной блокировки. Использование readonly гарантирует, что в этой переменной ссылка всегда на один и тот же объект и блокировка по нему всегда будет взаимной.
1
|
||
|
Заблокирован
|
||
| 18.10.2020, 14:15 [ТС] | ||
|
Но тогда ее и в коде можно использовать теоретически (не знаю зачем это может потребоваться)?
0
|
||
|
Модератор
|
|||||||||
| 18.10.2020, 14:18 | |||||||||
|
Но всегда надо гарантировать, что все lock из разных потоков обращаются к одному объекту. Обращение к одному изменяемому полю (или свойству) этого гарантировать не может. Пример потокозащищённого обращения к коллекции:
Но очень часто - можно сказать, практически всегда. Добавлено через 21 секунду
2
|
|||||||||
|
Заблокирован
|
||
| 18.10.2020, 14:22 [ТС] | ||
|
0
|
||
|
Модератор
|
||
| 18.10.2020, 14:31 | ||
|
В более сложных надо понимать, что пока работает один lock, то остальные ждут и методы в которых они объявлены остановлены. То есть lock приводит к торможению связанных методов. Допустим, если обращения на чтение частые, а потокозащищённость нужна только при записи/изменении объекта (поля, свойства), то можно рассмотреть вариант применения ReaderWriterLockSlim. В других случаях могут потребоваться иные решения.
0
|
||
|
Заблокирован
|
||
| 18.10.2020, 14:49 [ТС] | ||
|
0
|
||
|
17823 / 12973 / 3382
Регистрация: 17.09.2011
Сообщений: 21,261
|
|||||||
| 18.10.2020, 14:58 | |||||||
|
Стандартный способ — это lock. В принципе очень полезная привычка: по умолчанию поле объявлять как readonly и убирать этот модификатор только тогда, когда появится острая необходимость изменять его значение. Многопоточность — наверное, самая сложная часть в программировании, накосячить там — проще простого. Потому лучше заранее всячески себя обезопасить, максимально изолировав любые объекты, используемые при синхронизации. Очень легко повесить намертво приложение. Если объект используется для синхронизации, то нужно быть на 100% уверенным, что используется он только там, где его используете вы, т.е. иметь над ним полный контроль. Если у вас какое-то поле, используемое для чего-то еще, но вы не можете быть уверены, что в реализации этого класса где-нибудь не прописано lock (this), а если доступ к значению этого поля есть у внешних классов, то тут вообще никаких гарантий и никакой уверенности.Бывают ситуации, когда полезно лочиться на разных объектах в одном и том же методе. Например, когда есть группы объектов, между собой не связанные, но требующие синхронизации объектов в этой же группе. В этой ситуации хорошо иметь отдельный объект синхронизации для каждой группы.
3
|
|||||||
|
Заблокирован
|
|
| 18.10.2020, 15:08 [ТС] | |
|
Вывод - если синхронизация участка кода обеспечивается с помощью lоck, то соответствующую переменную создаем формально, в коде не используем, лепим на неё "для надежности" модификатор readonly.
P.S. Остался вопрос почему в примерах, как правило, используют для lock тип object? Придерживаться этого правила? Казалось бы, можно и int использовать, это не даст какую-нибудь экономию?
0
|
|
|
Модератор
|
||||
| 18.10.2020, 15:12 | ||||
|
Добавлено через 1 минуту Добавлено через 1 минуту В реальности возможных разных вариантов очень много.
1
|
||||
|
Заблокирован
|
||||||||
| 18.10.2020, 15:19 [ТС] | ||||||||
|
Я правильно понимаю, что если бы в данном примере в качестве объекта для lock использовался бы некий формальный объект, то всё работало бы точно так же? То есть код ниже столь же хорош (и даже лучше, поскольку меньше шансов накосячить впоследствии):
0
|
||||||||
|
Модератор
|
||||
| 18.10.2020, 15:28 | ||||
|
Но, допустим, у вас сложная логика, и есть статические методы по работе со с полем _numbers из разных экземпляров. Метод просто получает коллекцию List<int> и не знает из какого она экземпляра. В таком случае блокировку надо делать именно по самой коллекции полученной в параметрах. Добавлено через 1 минуту
1
|
||||
|
Заблокирован
|
||||||
| 30.10.2020, 16:38 [ТС] | ||||||
|
kolorotur,
мне представляется удобным использовать класс Interlocked для обеспечения потокобезопасности одной переменной. Но его методы не определены явно для всех типов (только для ряда типов). Какой метод Interlocked правильно использовать для перечислений? Можно, конечно, вспомнить, что перечисление можно преобразовать в int и потом обратно и применить метод Exchange(Int32, Int32). (хотя... сейчас пришло в голову, что наверное это может не получиться, ведь при этом возникнут прорехи в потокобезопасности в моменты преоразования из типа int в тип перечисления???) Но можно ли использовать Interlocked для перечислений без необходимости преобразования типа? Добавлено через 7 минут Тогда так - можно ли с помощью Interlocked обеспечить потокобезопасность переменной типа перечисления? К переменой применяется две операции - присвоение (изменение значения) и сравнение (в логике программы). Добавлено через 9 минут Нашел вот такое решение:
Добавлено через 11 минут Поскольку защищено изменение переменной )типа перечисления) Field, то само сравнение Field в программе можно выполнять обычным способом? Тем более, что в классе Interlocked защищенных операций сравнения (с возвратом типа bool) нет. Добавлено через 11 минут Нашел ещё паллиатив как раз на мою тему. Я использую перечисление для описания возможных состояний класса. Предлагают эти же состояния описать с помощью свойств readonly специального класса-состояния, вместо перечисления. А я так вначале и делал , потом перешел на перечисления и тут вспомнил про потокобезопасность (состояние может менять асинхронно). И оказалось, что обеспечить потокобезопасность переменой состояния типа перечисления сложнее, чем типа пользовательского класса (для класса есть методы Interlocked с параметрами типа object). Если я это правильно понимаю
0
|
||||||
|
Модератор
|
|||||||
| 30.10.2020, 16:40 | |||||||
|
Мне, кажется, вы совершено неверно понимаете как работает Interlocked.Для данного примера никакой большей потокозащищённости, чем обычная реализация свойства, это не даёт. Все операции присваивания Int32 и так атомарны. В том числе и для возврата return. А возвращаемое значение для Exchange вы всё равно не используете. Весь этот код по функции и потокозащищённости равнозначен обычному автоствойству:
1
|
|||||||
|
Заблокирован
|
|
| 30.10.2020, 16:47 [ТС] | |
|
Иными словами, автосвойство типа перечисление автоматически потокозащищено?
Имею ввиду под потокозащищеностью - атомарность (непрерываемость) операции изменения значения. Добавлено через 2 минуты Не, нужно подумать. Типы int ведь тоже защищают. Короче говоря, зависит от того, что как данная переменная используется в программе.
0
|
|
|
Модератор
|
|||||||||||||
| 30.10.2020, 16:59 | |||||||||||||
|
Добавлено через 4 минуты Если же операция ОДНА, то никакой защиты не нужно.
Да, и то пример неудачный. Даже для сложений максимум какая может быть ошибка, что после присвоения с значения a и b уже другие.Но с точки зрения потокозащищённости - это валидная ситуация. Не валидная, если меняются две переменные, а в операции будет участвовать у одной переменной новое значение, а у другой старое. На простом сложении примера не получится.
0
|
|||||||||||||
|
Заблокирован
|
|
| 30.10.2020, 18:43 [ТС] | |
|
В общем, нужно различать защиту конкретной операции с переменной и защиту алгоритма (куска кода, в котором возможны коллизии из-за асинхронности). Interlocked это про защиту операции.
0
|
|
|
Модератор
|
||||||||||||||||||
| 30.10.2020, 19:31 | ||||||||||||||||||
|
Допустим, Add объединяет в один атомарный блок
CompareExchange:
Добавлено через 6 минут Нет никакого смысла для атомарных типов защищать get {return _field;} и set {_field = value;}.Эти операции и так производятся одной командой процессора и никакие потоки вмещаться в это не могут. Для неатомарных типов (структур с полями, long на x86 и др.) эти операции уже требуют защиты. Добавлено через 58 секунд Если ваше перечисление не long под сборку х86, то для него тоже нет необходимости в защите.
0
|
||||||||||||||||||
| 30.10.2020, 19:31 | |
|
Помогаю со студенческими работами здесь
20
Потокобезопасность статических элементов Потокобезопасность ConcurrentDictionary vs Dictionary Потокобезопасность, найти ошибки в коде
Искать еще темы с ответами Или воспользуйтесь поиском по форуму: |
|
Новые блоги и статьи
|
|||
|
SDL3 для Desktop (MinGW): Рисуем цветные прямоугольники с помощью рисовальщика SDL3 на Си и C++
8Observer8 17.03.2026
Содержание блога
Финальные проекты на Си и на C++:
finish-rectangles-sdl3-c. zip
finish-rectangles-sdl3-cpp. zip
|
Символические и жёсткие ссылки в Linux.
algri14 15.03.2026
Существует два типа ссылок — символические и жёсткие.
Ссылка в Linux — это запись в каталоге, которая может указывать либо на inode «файла-ИСТОЧНИКА», тогда это будет «жёсткая ссылка» (hard link),. . .
|
[Owen Logic] Поддержание уровня воды в резервуаре количеством включённых насосов: моделирование и выбор регулятора
ФедосеевПавел 14.03.2026
Поддержание уровня воды в резервуаре количеством включённых насосов: моделирование и выбор регулятора
ВВЕДЕНИЕ
Выполняя задание на управление насосной группой заполнения резервуара,. . .
|
делаю науч статью по влиянию грибов на сукцессию
anaschu 13.03.2026
прикрепляю статью
|
|
SDL3 для Desktop (MinGW): Создаём пустое окно с нуля для 2D-графики на SDL3, Си и C++
8Observer8 10.03.2026
Содержание блога
Финальные проекты на Си и на C++:
hello-sdl3-c. zip
hello-sdl3-cpp. zip
Результат:
|
Установка CMake и MinGW 13.1 для сборки С и C++ приложений из консоли и из Qt Creator в EXE
8Observer8 10.03.2026
Содержание блога
MinGW - это коллекция инструментов для сборки приложений в EXE. CMake - это система сборки приложений. Здесь описаны базовые шаги для старта программирования с помощью CMake и. . .
|
Как дизайн сайта влияет на конверсию: 7 решений, которые реально повышают заявки
Neotwalker 08.03.2026
Многие до сих пор воспринимают дизайн сайта как “красивую оболочку”. На практике всё иначе: дизайн напрямую влияет на то, оставит человек заявку или уйдёт через несколько секунд.
Даже если у вас. . .
|
Модульная разработка через nuget packages
DevAlt 07.03.2026
Сложившийся в . Net-среде способ разработки чаще всего предполагает
монорепозиторий в котором находятся все исходники.
При создании нового решения, мы просто добавляем нужные проекты
и имеем. . .
|