|
0 / 0 / 0
Регистрация: 04.06.2022
Сообщений: 24
|
||||||
Вопрос по многопоточности18.07.2025, 22:33. Показов 13845. Ответов 104
Метки concurrency (Все метки)
Здравствуйте, сейчас смотрю книги по многопоточности, возникло несколько вопросов. Почему-то слово "вопрос" нельзя полностью написать в заголовке.
1. Известно, что переменную bool (или int, неважно) может 1 раз записать только 1 поток, остальные только читают, зачем тогда делать её atomic? 2. Улетят ли вызовы notify_one/notify_all вникуда, если они много раз вызваны перед методами, которые ожидают cv? 3. Допустим, есть 5 потоков и есть общий вектор с огромным количеством элементов. Первый поток изменяет только элементы с идексами 0, 5, 10; второй поток - элементы с индексами 1, 6, 11; третий поток - элементы с индексами 2, 7, 12 и т.д. Правильно ли я понимаю, что переброска кэша и связанное с ним замедление программы все равно может происходить, потому что индексы, с которыми работает каждый поток, находятся по соседству? 4. Вот пример потокобезопасной очереди из книги Вилльямса. Зачем при сравнении head с tail в функции get_tail мы используем мьютекс, который тут же перестает блокироваться после того, как мы вышли из функции?
0
|
||||||
| 18.07.2025, 22:33 | |
|
Ответы с готовыми решениями:
104
Управление потоками в многопоточности Нужна информация о многопоточности |
|
фрилансер
6454 / 5655 / 1129
Регистрация: 11.10.2019
Сообщений: 15,054
|
||
| 19.07.2025, 08:42 | ||
|
Но если была гарантия, что переменная уже инициализирована и больше меняться не будет, а только потом были запущены читающие потоки, то всё ок
1
|
||
|
0 / 0 / 0
Регистрация: 04.06.2022
Сообщений: 24
|
|||||||||
| 20.07.2025, 15:57 [ТС] | |||||||||
Добавлено через 9 минут Например, в этом коде может печататься на 123, а цифры в другом порядке, но если перед каждым bool поставить volatile или использовать atomic<bool>, то будет печататься 123, как и ожидали. Понятно, почему работает с atomic или volatile , но почему без них не работает?
0
|
|||||||||
|
фрилансер
6454 / 5655 / 1129
Регистрация: 11.10.2019
Сообщений: 15,054
|
|||
| 20.07.2025, 18:45 | |||
std::atomic - решаетА вывод в std::cout здесь может замаскировать проблему, так как к нему доступ синхронизирован внутри класса
1
|
|||
| 20.07.2025, 21:03 | |||
1
|
|||
|
0 / 0 / 0
Регистрация: 04.06.2022
Сообщений: 24
|
||
| 20.07.2025, 22:18 [ТС] | ||
|
"TBB provides threadsafe containers and some parallel algorithms, whereas OpenMP is more of a way to parallelise existing code." "TBB предоставляет потокобезопасные контейнеры и некоторые параллельные алгоритмы, тогда как OpenMP — это скорее способ распараллелить существующий код." Похоже, что с TBB надо ознакомиться, а OpenMP изучить более внимательно, так? Посоветуйте, пожалуйста, литературу, а также то, с чего начать с TBB или с OpenMP .
0
|
||
| 20.07.2025, 23:51 | ||||||||
0
|
||||||||
|
6352 / 3523 / 1428
Регистрация: 07.02.2019
Сообщений: 8,995
|
|||||
| 21.07.2025, 13:50 | |||||
tail не под блокировкой в функции get_tail(), то конечно же будет.Это конкурентная операция чтения и она, как минимум, должна быть атомарной. Но, что еще более важно, тут необходимо обеспечить межпоточную синхронизацию: в функции push() три операции записи (на самом деле их там сколь угодно много), и поток, выполняющий pop(), должен увидеть их именно в том порядке, в котором их делает поток, выполняющий push() (что будет при нарушении консистентности данных, можете пофантазировать самостоятельно). Мьютекс обеспечивает синхронизацию acquire/release.
2
|
|||||
|
0 / 0 / 0
Регистрация: 04.06.2022
Сообщений: 24
|
||||
| 21.07.2025, 19:07 [ТС] | ||||
|
Если очередь пустая, то мы получаем старое значение tail (tail==head), возвращаем пустое значение, а далее нам не важно, что делает push, главное, что с помощью мьютекса внутри get_tail сравнение происходит уже с копией старого значение и не произошло UB по причине одновременного чтения и записи по одному адресу. А то, что значение tail в пустой очереди могло поменяться, это уже никак не волнует, правильно?
0
|
||||
|
6352 / 3523 / 1428
Регистрация: 07.02.2019
Сообщений: 8,995
|
||
| 21.07.2025, 20:13 | ||
|
Например, представьте, что очередь пуста, и два потока "одновременно" осуществляют доступ - один pop(), второй push(). Тот, который делает push(), увидел изменение tail (очередь не пуста), но не увидел, например, изменения в head->next (он по-прежнему nullptr), что в этом случае произойдет?
0
|
||
| 21.07.2025, 21:41 | ||||||||||
0
|
||||||||||
|
0 / 0 / 0
Регистрация: 04.06.2022
Сообщений: 24
|
|||||||||||||||||
| 21.07.2025, 22:36 [ТС] | |||||||||||||||||
0
|
|||||||||||||||||
|
6352 / 3523 / 1428
Регистрация: 07.02.2019
Сообщений: 8,995
|
|||||||||
| 21.07.2025, 23:56 | |||||||||
|
Не по теме:
[basic.exec] Так вот, под "порядком" я имел ввиду, что нужны гаранти того, что, например, запись tail->data в push happens before чтения head->data в pop.И это база языка, которую неплохо бы освоить. В конце концов кому-то же придется в этом разбираться и поддерживать, когда все существующие обитатели "дурки" отойдут дел. cdcodecpp, вы пока летите вперед паровоза. Пока просто примите то, что чтение tail не должно быть конкурентным с его записью, поэтому нужен mutex. Кликните здесь для просмотра всего текста
Чуть позже, в 5 главе, по-моему, вы познакомитесь с атомарными операциями и узнаете, что порядок модификации памяти объектов одним потоком может отличаться от наблюдаемого другим, т.е.:
0
|
|||||||||
|
0 / 0 / 0
Регистрация: 04.06.2022
Сообщений: 24
|
|||||||||||||
| 22.07.2025, 00:09 [ТС] | |||||||||||||
Кроме предотвращения данного UB мьютекс решает ещё какие-либо проблемы? Появятся ли проблемы без мьютекса именно у тех 2 строк, которые написаны ниже?
0
|
|||||||||||||
| 22.07.2025, 01:15 | |||||||
Что мне будет если пишу/читаю одновременно? Получу старое значение tail (но не мусор) и не сделаю pop (который был возможен)? Так мне все равно с этим надо считаться, push мог просто случиться позже. Вот если бы стал лезть внутрь старого tail - тогда да. Детский пример
![]() Не по теме: За ссылки на стандарт спасибо, но его нужно читать только когда совершенно точно известно что найти. По-другому у меня никогда не выходило :)
0
|
|||||||
|
6352 / 3523 / 1428
Регистрация: 07.02.2019
Сообщений: 8,995
|
||||||
| 22.07.2025, 15:38 | ||||||
|
К UB приводят не какие-то события во время выполнения, а ошибки в написании кода. UB буквально переводится как неопределенное поведение. Т.е. нет смысла вообще рассуждать, как и что будет происходить в работающей программе, её поведение не определено с точки зрения языка. На самом деле она конечно же ведет себя вполне определенно, и вы можете это поведение исследовать анализируя машинный код, но это все не имеет смысла и я попытаюсь объяснить почему. Нет такого понятия "одновременно" в языке. Вы пытаетесь представить выполнение кода так, как он написан на высокоуровневом языке, да еще и построчно. Но нужно понимать, что это всего лишь умозрительный эксперимент, который не будет иметь отношения к реальности. Такой подход может как помогать в усвоении материала, так и вредить. В вашем случае скорее второе. Вы должны понимать, одна строчка кода на с++ будет превращена компилятором в несколько(иногда сотни и тысячи) машинных инструкций, среди которых будут инструкции записи и чтения памяти. В погоне за производительностью компилятору позволено переупорядочивать эти инструкции так, как он считает нужным, если это не нарушает требования стандарта. Кликните здесь для просмотра всего текста
Например, если на определенной платформе операции записи в соседние ячейки памяти быстрее, а ваш код развернулся в последовательность записей по адресам A и B в одной строке, и A + 1 в следующей, то очевидной оптимизацией будет переупорядочить их в последовательность A, A + 1, B.
Кликните здесь для просмотра всего текста
Да, знание "нижнего" уровня компьютерных технологий прояснит суть и причины высокоуровневых правил, но не является необходимым. Если вы не собираетесь работать на этом уровне, конечно же. Просто там огромный объем информации.
Итак, резюмируя вышесказанное, отвечу на ваш вопрос: get_tail() весь код некорректен, он не соответствует стандарту и содержит UB. Говорить о проблемах в каких либо строках не имеет смысла.2) Если вас интересует, почему чтение tail мы делаем под мьютексом, а чтение остального без (и нет ли тут проблемы), то ответ: захват мьютекса в get_tail() как бы решает две задачи - предоставляет исключительный доступ к tail напрямую(как бы делая его атомарным) и опосредованно упорядочивая (предоставляет единый глобальный порядок модификации памяти) доступ к остальному. Но подробно об этом вы узнаете чуть позже, пока не заморачивайтесь по этому поводу, всему свое время.Не по теме:
Что за детский сад? Что вы от меня хотите? Вы вроде ясно дали понять, что это трудно, вы в этом не разбираетесь и, самое главное, не хотите разбираться из-за опасений попасть в дурку. Зачем я буду тратить свое время на жевание кактуса? Если подойдете к вопросу серьезно, но возникнут трудности в понимании конкретных пунктов стандарта, я постараюсь помочь. Заниматься демагогией с вами я не собираюсь.
0
|
||||||
|
0 / 0 / 0
Регистрация: 04.06.2022
Сообщений: 24
|
|||||||
| 22.07.2025, 23:07 [ТС] | |||||||
А если бы команды не переупорядочивались компилятором и процессором, то всё равно было бы UB?
0
|
|||||||
| 23.07.2025, 00:46 | |||
|
1. Такое UB недопустимо, ошибка, нужно исправлять! Даже если сейчас нет проблем, они могут возникнуть в будущем! Такие ответы легко даются, когда "меня это не коснется", когда не нужно править старый код, часто писаный другими в незапамятные времена 2. Ничем особенным это UB не грозит, да, читающий "увидит" старое значение, это необязательно катастрофа. И вообще: "работает - не лезь" (хотя это конечно ничего не доказывает, баги всплывали и через годы). Да, это мое мнение 3. Хз, что такое "UB" - никто не знает. На всякий случай сделайте theMax atomic'ом, хуже не будет Вполне нормальный ответ практика 4. Это может быть корректно исправлено, для этого надо <..>. Идеальный ответ которого не случится. Ну, для полноты картины/списка
0
|
|||
| 23.07.2025, 01:46 | ||
|
Или вот др пример из той же книги (аттач). Далее там довольно пространные объяснения вникнуть в которые непросто. Поэтому "верно ли я понимаю что"
1
|
||
| 23.07.2025, 01:46 | |
|
Помогаю со студенческими работами здесь
20
изучение многопоточности Объясните принцип создания многопоточности Менеджмент жесткого диска при многопоточности Реализация многопоточности в консоли Сравнение многопоточности С++11 и WinAPI Искать еще темы с ответами Или воспользуйтесь поиском по форуму: |
|
| Опции темы | |
|
|
Новые блоги и статьи
|
|||
|
SDL3 для Web (WebAssembly): Обработчик клика мыши в браузере ПК и касания экрана в браузере на мобильном устройстве
8Observer8 02.02.2026
Содержание блога
Для начала пошагово создадим рабочий пример для подготовки к экспериментам в браузере ПК и в браузере мобильного устройства. Потом напишем обработчик клика мыши и обработчик. . .
|
Философия технологии
iceja 01.02.2026
На мой взгляд у человека в технических проектах остается роль генерального директора. Все остальное нейронки делают уже лучше человека. Они не могут нести предпринимательские риски, не могут. . .
|
SDL3 для Web (WebAssembly): Вывод текста со шрифтом TTF с помощью SDL3_ttf
8Observer8 01.02.2026
Содержание блога
В этой пошаговой инструкции создадим с нуля веб-приложение, которое выводит текст в окне браузера. Запустим на Android на локальном сервере. Загрузим Release на бесплатный. . .
|
SDL3 для Web (WebAssembly): Сборка C/C++ проекта из консоли
8Observer8 30.01.2026
Содержание блога
Если вы откроете примеры для начинающих на официальном репозитории SDL3 в папке: examples, то вы увидите, что все примеры используют следующие четыре обязательные функции, а. . .
|
|
SDL3 для Web (WebAssembly): Установка Emscripten SDK (emsdk) и CMake для сборки C и C++ приложений в Wasm
8Observer8 30.01.2026
Содержание блога
Для того чтобы скачать Emscripten SDK (emsdk) необходимо сначало скачать и уставить Git: Install for Windows. Следуйте стандартной процедуре установки Git через установщик. . . .
|
SDL3 для Android: Подключение Box2D v3, физика и отрисовка коллайдеров
8Observer8 29.01.2026
Содержание блога
Box2D - это библиотека для 2D физики для анимаций и игр. С её помощью можно определять были ли коллизии между конкретными объектами. Версия v3 была полностью переписана на Си, в. . .
|
Инструменты COM: Сохранение данный из VARIANT в файл и загрузка из файла в VARIANT
bedvit 28.01.2026
Сохранение базовых типов COM и массивов (одномерных или двухмерных) любой вложенности (деревья) в файл, с возможностью выбора алгоритмов сжатия и шифрования.
Часть библиотеки BedvitCOM
Использованы. . .
|
SDL3 для Android: Загрузка PNG с альфа-каналом с помощью SDL_LoadPNG (без SDL3_image)
8Observer8 28.01.2026
Содержание блога
SDL3 имеет собственные средства для загрузки и отображения PNG-файлов с альфа-каналом и базовой работы с ними. В этой инструкции используется функция SDL_LoadPNG(), которая. . .
|