Форум программистов, компьютерный форум, киберфорум
C++
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
 
0 / 0 / 0
Регистрация: 04.06.2022
Сообщений: 24

Вопрос по многопоточности

18.07.2025, 22:33. Показов 15004. Ответов 104

Студворк — интернет-сервис помощи студентам
Здравствуйте, сейчас смотрю книги по многопоточности, возникло несколько вопросов. Почему-то слово "вопрос" нельзя полностью написать в заголовке.

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 мы используем мьютекс, который тут же перестает блокироваться после того, как мы вышли из функции?

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
#include <iostream>
#include <fstream>
#include <ios>
#include <string>
#include <numeric>
#include <map>
#include <vector>
#include <queue>
#include <iterator>
#include <memory>
#include <mutex>
#include <type_traits>
#include <algorithm>
#include <atomic>
#include <thread>
#include <chrono>
#include <cassert>
 
// clang -std=c++2a -m64 -o thread_safe_queue.exe thread_safe_queue.cpp
 
template<typename T> class thread_safe_queue {
private:
    struct node {
        std::shared_ptr<T> data;
        std::unique_ptr<node> next;
    };
    std::unique_ptr<node> head;
    node* tail;
 
    mutable std::mutex m_head;
    mutable std::mutex m_tail;
 
public:
    thread_safe_queue(const thread_safe_queue& ) = delete;
    thread_safe_queue() : head(new node()), tail(head.get()) {}
 
    node* get_tail() const {
        std::lock_guard<std::mutex> lg_tail(m_tail);
        return tail;
    }
 
    bool empty() const {
        std::lock_guard<std::mutex> lg_head(m_head);
        std::lock_guard<std::mutex> lg_tail(m_tail);
        return (head.get() == tail);
    }
 
    std::shared_ptr<T> pop() {
        std::lock_guard<std::mutex> lg_head(m_head);
        if (head.get() == get_tail()) { // why ?
            return std::shared_ptr<T>();
        }
 
        std::shared_ptr<T> res(head->data);
        std::unique_ptr<node> old_head = std::move(head);
        head = std::move(old_head->next);
        return res;
    }
 
    void push(const T new_value) {
        std::unique_ptr<node> q(new node);
        std::lock_guard<std::mutex> lg_tail(m_tail);
        tail->data = std::make_shared<T>(std::move(new_value));
        tail->next = std::move(q);
        tail = tail->next.get();
    }
};
 
int main(int argc, char *argv[]) {
    return 0;
}
0
cpp_developer
Эксперт
20123 / 5690 / 1417
Регистрация: 09.04.2010
Сообщений: 22,546
Блог
18.07.2025, 22:33
Ответы с готовыми решениями:

Соотношение многопоточности приложения c++ и многопоточности на уровне системы?
Возник следующий вопрос: в C++ существует два варианта работы с многопоточностью - std::theard и...

Управление потоками в многопоточности
вопрос простой: что посоветуете почитать по теме для начинающего? с помощью чего проще...

Нужна информация о многопоточности
дайте хорошую статью про создание многопоточных приложений...

104
Эксперт функциональных языков программированияЭксперт С++
 Аватар для Royal_X
6221 / 2917 / 1046
Регистрация: 01.06.2021
Сообщений: 10,793
14.08.2025, 20:54
Студворк — интернет-сервис помощи студентам
как вообще можно велосипеды писать, когда в С++ столько вкусных функций https://en.cppreference.com/w/cpp/atomic.html ?
0
267 / 199 / 30
Регистрация: 26.11.2022
Сообщений: 866
14.08.2025, 23:43
Royal_X, ну сделайте с этими недоделанными вкусностями работу с NUMA, привязку потоков к ядрам процессоров, приоритеты потоков и пр.
Пока вы пишите простое десктопное приложение - вам хватит и стандартных "вкусностей", а потом вдруг появится задача где не только велосипеды придётся писать, но и колёса к ним проектировать.
Всегда надо помнить что стандартная библиотека с++ это идеал кода, а ширпотреб, который кое-как подходит для большинства применений.

Даже спин локи можно сделать по разному:
простой спинер,
спинер с гарантированной очерёдностью доступа,
к каждому из них можно добавить стратегию "back-off", чтобы потоки не долбились атомарными операциями в одну ячейку памяти.
0
Эксперт функциональных языков программированияЭксперт С++
 Аватар для Royal_X
6221 / 2917 / 1046
Регистрация: 01.06.2021
Сообщений: 10,793
14.08.2025, 23:57
Цитата Сообщение от Aledveu Посмотреть сообщение
Всегда надо помнить что стандартная библиотека с++ это идеал кода, а ширпотреб
наверное, вы хотели сказать "не идеал кода...".

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

Цитата Сообщение от Aledveu Посмотреть сообщение
ну сделайте с этими недоделанными вкусностями работу с NUMA, привязку потоков к ядрам процессоров, приоритеты потоков и пр.
полагаю, что наверняка существуют очень крутые профи библиотеки для всего этого. Практика показывает, что в интернете находится готовое решение почти под любую задачу.
0
267 / 199 / 30
Регистрация: 26.11.2022
Сообщений: 866
15.08.2025, 00:05
Цитата Сообщение от Royal_X Посмотреть сообщение
вы хотели сказать "не идеал кода...".
Да, простите, опечатался.

Цитата Сообщение от Royal_X Посмотреть сообщение
Практика показывает, что в интернете находится готовое решение почти под любую задачу.
Вы правы, но есть одно маленькое "но" - приходится перелопатить огромное количество исходников, и только потом наступает просветление и понимаешь - что 98% того что доступно - это поделки студентов, а то где люди реально заморочились и разобрались и показали что можно выжать из кода - это редкость.
0
1969 / 825 / 115
Регистрация: 01.10.2012
Сообщений: 4,924
Записей в блоге: 2
15.08.2025, 00:44
Цитата Сообщение от Aledveu Посмотреть сообщение
..ширпотреб, который кое-как подходит для большинства применений.
На это можно посмотреть иначе: это большой прогресс по сравнению с тем что было на эту тему в std до С++ 11
Цитата Сообщение от Aledveu Посмотреть сообщение
Даже спин локи можно сделать по разному:
простой спинер,
спинер с гарантированной очерёдностью доступа,
к каждому из них можно добавить стратегию "back-off", чтобы потоки не долбились атомарными операциями в одну ячейку памяти.
С удовольствием приму участие в обсуждении всего этого. Но сначала давайте разберемся с рекурсивным спиннером, это простая задачка

Цитата Сообщение от Royal_X Посмотреть сообщение
но мне очень далеко до тех задач, когда нужно самому реализовать что-то, что должно быть круче библиотечных функций.
Ну освоить простые вещи можно и без мега-задач. Вот утверждается что этот псевдокод неверен
Кликните здесь для просмотра всего текста
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// Внимание: это пример НЕВЕРЕН
 
// ждем пока спиннер освободится
while (condition)
 std::this_thread::yield();
 
// снова захватываем спиннер
condition = 1;
 
// выполняем код "критической секции"
...
DoSomething();
..
 
// освобождаем спиннер
condition = 0;
А почему неверен? Где ошибка? Попробуйте разобраться, и не смущайтесь, Вы не хуже других
0
267 / 199 / 30
Регистрация: 26.11.2022
Сообщений: 866
15.08.2025, 00:52
между строками 4 и 8 другой поток может захватить спиннер
0
Эксперт функциональных языков программированияЭксперт С++
 Аватар для Royal_X
6221 / 2917 / 1046
Регистрация: 01.06.2021
Сообщений: 10,793
15.08.2025, 01:35
Igor3D, condition устанавливается без мьютексов или атомарных операций. Несколько потоков одновременно могут увидеть condition = 0 и войти в критическую секцию. Возможен захват спиннера после выхода из цикла, но до входа в критическую секцию. Ещё нет барьеров памяти, полагаю, что нужен memory_order_acquire. В любом случае библиотечных функций достаточно для решения этой проблемы.
0
1969 / 825 / 115
Регистрация: 01.10.2012
Сообщений: 4,924
Записей в блоге: 2
15.08.2025, 02:07
Цитата Сообщение от Royal_X Посмотреть сообщение
В любом случае библиотечных функций достаточно для решения этой проблемы.
Ну хорошо, исправьте код применив нужные ф-ции
0
267 / 199 / 30
Регистрация: 26.11.2022
Сообщений: 866
15.08.2025, 08:28
Royal_X, и ваш код превратисля из спинлока в обычный современный библиотечный мьютекс, который кстати делается на фьютексах https://github.com/eliben/code... -futex.cpp

какой смысл делать спинлок, если вы вызываете ОС в цикле std::this_thread::yield(); ?
0
1969 / 825 / 115
Регистрация: 01.10.2012
Сообщений: 4,924
Записей в блоге: 2
16.08.2025, 12:57
Цитата Сообщение от Igor3D Посмотреть сообщение
Ну хорошо, исправьте код применив нужные ф-ции
Ну и..? Royal_X, конечно Вы не обязаны что-то писать, но если, как Вы говорите, std:: так уж хорош и самодостаточен, то почему бы не показать его богатырскую силу на 5 строчках простого кода? Ладно, попробую я
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// пытаемся захватить спиннер
while (true) {
 int expected = 0;
 if (condition.compare_exchange_strong(expected, 1)) 
  break;
 std::this_thread::yield();
}
 
// выполняем код "критической секции"
...
DoSomething();
..
 
// освобождаем спиннер
condition.store(0);
Писал здесь, возможны ошибки. Как видим, чтение в цикле (предыдущий, неверный вариант) ничего не дает. Да, можем дождаться condition = false и выскочить из цикла, но перед выполнением следующей команды condition может быть уже установлено в true другим потоком. Выходит спиннер могут одновременно захватить 2 и более потоков.

Вместо этого есть простой и хороший способ захвата: CAS, говорят также "идиома CAS". На уровне процессора гарантируется что condition будет установлено (конкретно в 1 в нашем случае) только если его текущее значение = заданному (у нас = 0). Таким образом если 2 или более потоков выполняют этот код, то один (и только один) установит значение 1 и выскочит из while, т.е. этот поток захватит спиннер, остальные останутся крутиться в цикле пока захватчик не обнулит condition.

В общем, утверждение типа "спиннер что-то читает в цикле" неверно, правильно сказать "спиннер пытается писать в цикле", удачная запись означает захват. Справедливости ради надо сказать что упереться рогом и обойтись без CAS все-таки можно, но это опасно для Ваших психики/здоровья, а практический эффект почти нулевой.

Ладно, поехали дальше. Мы ведь хотели не просто спиннер, а рекурсивный. Какие есть мысли?
0
16.08.2025, 13:10

Не по теме:

Igor3D, я не пишу код ради написания кода. Напиши прикладную задачу, а я напишу код. Имею в виду, не говори мне, как реализовать внутренне. Рекурсивный или куерсивный, я сам решу. Ты пиши задачу, а я сам решу, что использовать, а что нет.

0
267 / 199 / 30
Регистрация: 26.11.2022
Сообщений: 866
16.08.2025, 13:55
Если мне не изменяет память то была научная работа где доказывалось что CAS является минимально необходимой аппаратной функцией процессора или какого либо блока системы для обеспечения синхронизации потоков.
0
фрилансер
 Аватар для Алексей1153
6461 / 5664 / 1130
Регистрация: 11.10.2019
Сообщений: 15,080
16.08.2025, 14:01
Igor3D, рекурсивный мьютекс - это дикий антипаттерн. Зачем пытаться его сделать?
0
1969 / 825 / 115
Регистрация: 01.10.2012
Сообщений: 4,924
Записей в блоге: 2
16.08.2025, 20:14
Вот 3 последних ответа. Первый - человек впадает в амбицию и злобно тыкает Второй - упоминание о научной работе (видимо серьезной). Третий - это ж антипаттерн, мол, так вообще делать не нужно. В общем, что угодно - лишь бы не работать. Зачем? Зачем прилагать такие усилия чтобы отмазаться от написания несчастных 5 строчек кода? Может проще и лучше их взять да написать, а потом уже можно и покалякать "насколько это нужно/хорошо"?
0
фрилансер
 Аватар для Алексей1153
6461 / 5664 / 1130
Регистрация: 11.10.2019
Сообщений: 15,080
16.08.2025, 20:41
Цитата Сообщение от Igor3D Посмотреть сообщение
В общем, что угодно - лишь бы не работать
в общем, с тобой всё понятно
0
 Аватар для abit
870 / 529 / 149
Регистрация: 03.02.2013
Сообщений: 1,859
17.08.2025, 16:23
"рекурсивный мьютекс - это дикий антипаттерн"
А в плюсах традиция тащить антипттерны в std?
0
Эксперт функциональных языков программированияЭксперт С++
 Аватар для Royal_X
6221 / 2917 / 1046
Регистрация: 01.06.2021
Сообщений: 10,793
17.08.2025, 16:54
abit, в std много чего есть такого, что не нужно использовать, например, https://en.cppreference.com/w/... /atoi.html

Программисту дан мозг, чтобы думать, что использовать, а что нет, а не тупо использовать все, что есть в std. Некоторые функции в std для использования на свой страх и риск для отдельных извращенных сценариев.
0
фрилансер
 Аватар для Алексей1153
6461 / 5664 / 1130
Регистрация: 11.10.2019
Сообщений: 15,080
17.08.2025, 17:30
abit, я примерно про него и говорил

ещё есть goto

ещё есть using namespace std

ещё есть макросы

ещё есть глобальные переменные

много чего есть "интересного"
0
 Аватар для abit
870 / 529 / 149
Регистрация: 03.02.2013
Сообщений: 1,859
17.08.2025, 18:35
Зато полезные фичи из boost можно по 20 лет настаивать...
0
фрилансер
 Аватар для Алексей1153
6461 / 5664 / 1130
Регистрация: 11.10.2019
Сообщений: 15,080
17.08.2025, 20:28
abit, кто пользуется полезными фичами из буста - может просто продолжить ими пользоваться
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
raxper
Эксперт
30234 / 6612 / 1498
Регистрация: 28.12.2010
Сообщений: 21,154
Блог
17.08.2025, 20:28
Помогаю со студенческими работами здесь

изучение многопоточности
с чего стоит начать изучение многопоточности? есть базовые знания по С++, основы ООП. пытался...

Объясните принцип создания многопоточности
Здраствуйте, объясните пожалйста как сделать программу многопоточной, у меня есть одна программа, в...

Менеджмент жесткого диска при многопоточности
Пусть у меня 4-ех ядерный процессор, и запущено 4 рабочих потока (в одном процессе). Казалось бы,...

Реализация многопоточности в консоли
Доброго времени суток. Не могу разобраться в многопоточности. Реализовано перемещение по меню с...

Сравнение многопоточности С++11 и WinAPI
У меня скорее теоретический вопрос, чем практический. Есть ли разница работы с многопоточностью в...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
100
Ответ Создать тему
Новые блоги и статьи
SDL3 для Web (WebAssembly): Синхронизация спрайтов SDL3 и тел Box2D
8Observer8 04.03.2026
Содержание блога Финальная демка в браузере. Итоговый код: finish-sync-physics-sprites-sdl3-c. zip На первой гифке отладочные линии отключены, а на второй включены:. . .
SDL3 для Web (WebAssembly): Идентификация объектов на Box2D v3 - использование userData и событий коллизий
8Observer8 02.03.2026
Содержание блога Финальная демка в браузере. Итоговый код: finish-collision-events-sdl3-c. zip https:/ / www. cyberforum. ru/ blog_attachment. php?attachmentid=11680&amp;d=1772460536 Одним из. . .
Реалии
Hrethgir 01.03.2026
Нет, я не закончил до сих пор симулятор. Эта задача сложнее. Не получилось уйти в плавсостав, но оно и к лучшему, возможно. Точнее получалось - но сварщиком в палубную команду, а это значит, в моём. . .
Ритм жизни
kumehtar 27.02.2026
Иногда приходится жить в ритме, где дел становится всё больше, а вовлечения в происходящее — всё меньше. Плотный график не даёт вниманию закрепиться ни на одном событии. Утро начинается с быстрых,. . .
SDL3 для Web (WebAssembly): Сборка библиотек: SDL3, Box2D, FreeType, SDL3_ttf, SDL3_mixer и SDL3_image из исходников с помощью CMake и Emscripten
8Observer8 27.02.2026
Недавно вышла версия 3. 4. 2 библиотеки SDL3. На странице официальной релиза доступны исходники, готовые DLL (для x86, x64, arm64), а также библиотеки для разработки под Android, MinGW и Visual Studio. . . .
SDL3 для Web (WebAssembly): Реализация движения на Box2D v3 - трение и коллизии с повёрнутыми стенами
8Observer8 20.02.2026
Содержание блога Box2D позволяет легко создать главного героя, который не проходит сквозь стены и перемещается с заданным трением о препятствия, которые можно располагать под углом, как верхнее. . .
Конвертировать закладки radiotray-ng в m3u-плейлист
damix 19.02.2026
Это можно сделать скриптом для PowerShell. Использование . \СonvertRadiotrayToM3U. ps1 <path_to_bookmarks. json> Рядом с файлом bookmarks. json появится файл bookmarks. m3u с результатом. # Check if. . .
Семь CDC на одном интерфейсе: 5 U[S]ARTов, 1 CAN и 1 SSI
Eddy_Em 18.02.2026
Постепенно допиливаю свою "многоинтерфейсную плату". Выглядит вот так: https:/ / www. cyberforum. ru/ blog_attachment. php?attachmentid=11617&stc=1&d=1771445347 Основана на STM32F303RBT6. На борту пять. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru