1 / 1 / 0
Регистрация: 08.08.2021
Сообщений: 18
|
||||||||||||||||
1 | ||||||||||||||||
Энтони Уильямс. - 7.2.5. Применение модели памяти к свободному от блокировок стеку04.07.2022, 15:12. Показов 2752. Ответов 4
Доброго времени суток.
Начал читать книгу - Параллельное программирование на С++ в действии (перевод на русский язык ДМК Пресс). Столкнулся с проблемой в понимании раздела 7.2.5, где приводится реализация стека с применением модели памяти к свободному от блокировок. Приведу листинг из книги: Кликните здесь для просмотра всего текста
И текст из книги, описывающий последнее ветвление кода: Кликните здесь для просмотра всего текста
Мы почти закончили, осталось только рассмотреть функции, в которых используются операции fetch_add(), изменяющие счетчик ссылок. Поток, который добрался до возврата данных из узла, может продолжать в твердой уверенности, что никакой другой поток не смо- жет модифицировать хранящиеся в узле данные. Однако любой поток, который потерпел неудачу при извлечении данных, знает, что какой-то другой поток данные в узле модифицировал; он использовал функцию swap() для извлечения данных. Следовательно, чтобы предотвратить гонку за данными мы должны гарантировать, что swap() происходит- раньше delete. Чтобы добиться этого, проще всего задать семантику std::memory_order_release при вызове fetch_add() в ветви, где мы возвращаем данные, и семантику std::memory_order_acquire – в ветви, где мы возвращаемся в начало цикла. Однако даже это перебор – лишь один поток выполняет delete (тот, что сбросил счетчик в нуль), поэтому только этому потоку нужно выполнить операцию захвата. К счастью, поскольку fetch_add() – операция чтения-модификации- записи, то она составляет часть последовательности освобождений, поэ- тому для достижения цели нам достаточно дополнительной операции load(). Если в ветви, где происходит возврат в начало цикла, счетчик ссылок уменьшается до нуля, то здесь же можно перезагрузить счетчик ссылок с семантикой std::memory_order_acquire, чтобы обеспечить требуемое отношение синхронизируется-с, а в самой операции fetch_ add() достаточно задать std::memory_order_relaxed. Как я понял, только один поток, который успел обнулить счётчик, должен выполнить операцию delete для переменной ptr (76 и 84 строчки кода). Чтобы этого добиться, необходимо, чтобы обе операции fetch_add имели отношение синхронизирован-с, но использовать семантику std::memory_order_acquire излишне, так как можно ограничится операцией захвата. В данном моменте у меня возникла проблема в понимании этого утверждения, так как автор использует в самой операции fetch_add() семантику std::memory_order_relaxed, а только потом в самом ветвлении операцию ptr->internal_count.load(std::memory_order_acquire); Из раздела 5.3.4. - Последовательности освобождений и отношение синхронизируется-с - привожу цитату, которая описывает ситуацию, когда цепочка операций составляет последовательность освобождений: Кликните здесь для просмотра всего текста
" операция сохранения помечена одним из признаков memory_order_release, memory_order_acq_rel или memory_order_ seq_cst, а операция загрузки – одним из признаков memory_order_ consume, memory_order_acquire или memory_order_seq_cst " В таком случае "первая в ней операция сохранения синхронизирует- ся-с (в случае memory_order_acquire или memory_order_seq_cst) или предшествует-по-зависимости (в случае memory_order_consume) последней операции загрузки". Будет предпочтительнее, если вы ответите на вопросы по каждому пункту: 1) В моём понимании, автор добивается синхронизации и предоставленный код
2) В дополнение к предыдущему пункту - Как тогда в коде автора происходит участие последней операции fetch_add() с семантикой std::memory_order_relaxed в последовательности освобождений (и операцией fetch_add() в ветвлении, где возвращается результат), если это противоречит тому, что было написано в разделе 5.3.4? std::memory_order_relaxed не позволит операции сохранения иметь отношение синхронизируется-с последней операции загрузки и гипотетически возможен случай, что оба потока попытаются очистить одну область памяти, так как internal_count не успевает обновиться.
0
|
04.07.2022, 15:12 | |
Ответы с готовыми решениями:
4
Недостаточно памяти стеку протоколов Tcp/ip Применение модели потенциальной ямы Применение кратной детерминированной модели Применение С++ модели (QObjectList) вместе с Qt Quick |
6340 / 3511 / 1427
Регистрация: 07.02.2019
Сообщений: 8,977
|
|
04.07.2022, 23:41 | 2 |
Сообщение было отмечено Sidr как решение
Решение
1) Да.
2) Нет никакого противоречия. Я главу не помню, а искать лень, но в книге было подробно про транзитивные свойства read-modify-write операций (fetch_add к ним относится). Т.е. операция ptr->internal_count.fetch_add(-1,std::memory_order_relaxed) является частью последовательности освобождения операции ptr->internal_count.fetch_add(count_increase,std::memory_order_release) (ссылка на стандарт).Проще говоря, в случае, если значение до декремента было 1, то это последняя rmw операция, а значит можно поставить барьер и вызвать деструктор.
1
|
1 / 1 / 0
Регистрация: 08.08.2021
Сообщений: 18
|
|
05.07.2022, 10:59 [ТС] | 3 |
Очень хороший ответ на вопрос, спасибо большое!
Нам необходимо по словам автора предотвратить гонку за данными, и для этого мы должны гарантировать, что swap() происходит-раньше delete. Я понял, что барьер ptr->internal_count.load(std::memory_order_acquire); не нужен для последней rmw операции (нужен для другой цели), так как срабатывает исправно даже с расслабленной моделью памяти.Обнуление счётчика уже является гарантией того, что только один поток может вызвать операцию delete, так как декремент атомарен - это легко понять - но это не есть цель автора. Если не окажется затруднительным, помогите, пожалуйста, ответить на эти вопросы: 1) 2) Разве не должно использоваться отношение происходит-раньше между swap() и delete (для реализации которого используется цикл), вместо отношения синхронизируется-с?
0
|
6340 / 3511 / 1427
Регистрация: 07.02.2019
Сообщений: 8,977
|
|
05.07.2022, 14:52 | 4 |
Сообщение было отмечено Sidr как решение
Решение
Нет, этот барьер как раз и нужен только для последеней rmw операции, т.к. именно она и должна синхронизироваться. То, что у вас по вашему мнению работает исправно - ничего не значит. Чтобы увидеть UB, нужна архитектура с поддержкой relaxed семантики и определенная доля "удачи". На x86-64, например, все relaxed операции на самом деле имеют семантику acquire-release.
Суть барьера не в том, чтобы только один поток выплнил delete. Барьеры упорядочивают операции вокруг атомарных операций. В данном конкретном случае барьер гарантирует, что при delete в деструкторе узла будет уничтожен актуальный shared_ptr на данные, т.е. межпоточно упорядочивает swap и delete. Т.е. переходя к вашим пунктам вопросам: 1) ptr->internal_count.load(std::memory_order_acquire) (операция С) транзитивно через ptr->internal_count.fetch_add(-1,std::memory_order_relaxed) (операция B) синхронизируется-с ptr->internal_count.fetch_add(count_increase,std::memory_order_release) (операция А). В даннм случае проверять значение после загрузки не нужно, т.к. оно гарантированно будет равно 0. Никто между декрементом и загрузкой не "влезет".2) Т.к. swap происходит-раньше операции A, операция С происходит-раньше delete, A синхронизируется-с С(а значит A происходит-раньше С) - следовательно swap происходит-раньше delete.
1
|
1 / 1 / 0
Регистрация: 08.08.2021
Сообщений: 18
|
|
05.07.2022, 16:27 [ТС] | 5 |
zayats80888, браво! Большое спасибо! Вы действительно очень сильно мне помогли понять это!
1
|
05.07.2022, 16:27 | |
05.07.2022, 16:27 | |
Помогаю со студенческими работами здесь
5
Применение объектно-ориентированной модели программирования Применение анимации к модели, созданной в 3Dmax Применение проверки достоверности к классу модели созданной entity framework Применение Динамического выделения памяти Работа кода из листинга из книги Энтони Уильямса Поиск картинки по свободному полю со списком Запись к свободному сотруднику в свободное время Искать еще темы с ответами Или воспользуйтесь поиском по форуму: |
|
Блоги программистов | |||||
Обновление сайта www.historian.by
Reglage 05.01.2025
Обещал подвести итоги 2024 года для сайта. Однако начну с того, что изменилось за неделю. Добавил краткий урок по последовательности действий при анализе вредоносных файлов и значительно улучшил урок. . .
|
Как использовать GraphQL в C# с HotChocolate
Programming 05.01.2025
GraphQL — это современный подход к разработке API, который позволяет клиентам запрашивать только те данные, которые им необходимы. Это делает взаимодействие с API более гибким и эффективным по. . .
|
Модель полного двоичного суматора с помощью логических операций (python)
AlexSky-coder 04.01.2025
def binSum(x:list, y:list):
s=^y]
p=x and y
for i in range(1,len(x)):
s. append((x^y)^p)
p=(x and y)or(p and (x or y))
return s
x=list()
y=list()
|
Это мы не проходили, это нам не задавали...(асихронный счётчик с управляющим сигналом задержки).
Hrethgir 04.01.2025
Асинхронный счётчик на сумматорах (шестиразрядный по числу диодов на плате, но наверное разрядов будет больше - восемь или шестнадцать, а диоды на старшие), так как триггеры прошли тестирование и. . .
|
Руководство по созданию бота для Телеграм на Python
IT_Exp 04.01.2025
Боты для Телеграм представляют собой автоматизированные программы, которые выполняют различные задачи, взаимодействуя с пользователями через интерфейс мессенджера. В данной статье мы рассмотрим,. . .
|
Применение компонентов PrimeVue в Vue.js 3 на TypeScript
BasicMan 04.01.2025
Введение в PrimeVue и настройка окружения
PrimeVue представляет собой мощную библиотеку компонентов пользовательского интерфейса для Vue. js 3, которая предоставляет разработчикам богатый набор. . .
|
Как стать Senior developer
cpp_developer 04.01.2025
В современной индустрии разработки программного обеспечения позиция Senior Developer представляет собой не просто следующую ступень карьерной лестницы, а качественно новый уровень профессионального. . .
|
Что известно о дате выхода Windows 12 и чего от нее ждать
IT_Exp 04.01.2025
В мире технологий постоянно происходят изменения, и операционные системы не являются исключением. Windows 11, выпущенная в октябре 2021 года, принесла множество инноваций и улучшений, но. . .
|
Что новенького в .NET Core 9
Programming 04.01.2025
Обзор ключевых изменений в . NET Core 9
Платформа . NET Core продолжает активно развиваться, и версия 9 представляет собой значительный шаг вперед в эволюции этой технологии. Новый релиз. . .
|
Инструкция по установке python3.13.1 в Debian 12
AlexSky-coder 03.01.2025
sudo apt update
sudo apt install build-essential zlib1g-dev libncurses5-dev libgdbm-dev libnss3-dev libssl-dev libreadline-dev libffi-dev
wget. . .
|
Затестил триггеры. архив проекта прилагаю с GOA файлами в настройках архиватора проектов.
Hrethgir 03.01.2025
В этот раз нет закольцованности, потому что от неё только глюки, как я понял, логика не вырезанная. Триггеры очень быстрые если верить измерениям с помощью анализатора от Gowin.
Есть ещё регистры,. . .
|
Python в помощь DevOps
IT_Exp 03.01.2025
Причины использования Python в работе DevOps
Python стал неотъемлемой частью мира DevOps, и это не случайно. Этот язык программирования обладает множеством преимуществ, которые делают его. . .
|