0 / 0 / 0
Регистрация: 04.06.2022
Сообщений: 24

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

18.07.2025, 22:33. Показов 19382. Ответов 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
Нарушитель
Эксперт функциональных языков программированияЭксперт С++
6331 / 3063 / 1054
Регистрация: 01.06.2021
Сообщений: 11,713
14.08.2025, 20:54
Студворк — интернет-сервис помощи студентам
как вообще можно велосипеды писать, когда в С++ столько вкусных функций https://en.cppreference.com/w/cpp/atomic.html ?
0
274 / 206 / 30
Регистрация: 26.11.2022
Сообщений: 903
14.08.2025, 23:43
Royal_X, ну сделайте с этими недоделанными вкусностями работу с NUMA, привязку потоков к ядрам процессоров, приоритеты потоков и пр.
Пока вы пишите простое десктопное приложение - вам хватит и стандартных "вкусностей", а потом вдруг появится задача где не только велосипеды придётся писать, но и колёса к ним проектировать.
Всегда надо помнить что стандартная библиотека с++ это идеал кода, а ширпотреб, который кое-как подходит для большинства применений.

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

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

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

Цитата Сообщение от Royal_X Посмотреть сообщение
Практика показывает, что в интернете находится готовое решение почти под любую задачу.
Вы правы, но есть одно маленькое "но" - приходится перелопатить огромное количество исходников, и только потом наступает просветление и понимаешь - что 98% того что доступно - это поделки студентов, а то где люди реально заморочились и разобрались и показали что можно выжать из кода - это редкость.
0
1980 / 836 / 115
Регистрация: 01.10.2012
Сообщений: 5,202
Записей в блоге: 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
274 / 206 / 30
Регистрация: 26.11.2022
Сообщений: 903
15.08.2025, 00:52
между строками 4 и 8 другой поток может захватить спиннер
0
Нарушитель
Эксперт функциональных языков программированияЭксперт С++
6331 / 3063 / 1054
Регистрация: 01.06.2021
Сообщений: 11,713
15.08.2025, 01:35
Igor3D, condition устанавливается без мьютексов или атомарных операций. Несколько потоков одновременно могут увидеть condition = 0 и войти в критическую секцию. Возможен захват спиннера после выхода из цикла, но до входа в критическую секцию. Ещё нет барьеров памяти, полагаю, что нужен memory_order_acquire. В любом случае библиотечных функций достаточно для решения этой проблемы.
0
1980 / 836 / 115
Регистрация: 01.10.2012
Сообщений: 5,202
Записей в блоге: 2
15.08.2025, 02:07
Цитата Сообщение от Royal_X Посмотреть сообщение
В любом случае библиотечных функций достаточно для решения этой проблемы.
Ну хорошо, исправьте код применив нужные ф-ции
0
274 / 206 / 30
Регистрация: 26.11.2022
Сообщений: 903
15.08.2025, 08:28
Royal_X, и ваш код превратисля из спинлока в обычный современный библиотечный мьютекс, который кстати делается на фьютексах https://github.com/eliben/code... -futex.cpp

какой смысл делать спинлок, если вы вызываете ОС в цикле std::this_thread::yield(); ?
0
1980 / 836 / 115
Регистрация: 01.10.2012
Сообщений: 5,202
Записей в блоге: 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
274 / 206 / 30
Регистрация: 26.11.2022
Сообщений: 903
16.08.2025, 13:55
Если мне не изменяет память то была научная работа где доказывалось что CAS является минимально необходимой аппаратной функцией процессора или какого либо блока системы для обеспечения синхронизации потоков.
0
фрилансер
 Аватар для Алексей1153
6504 / 5748 / 1134
Регистрация: 11.10.2019
Сообщений: 15,393
16.08.2025, 14:01
Igor3D, рекурсивный мьютекс - это дикий антипаттерн. Зачем пытаться его сделать?
0
1980 / 836 / 115
Регистрация: 01.10.2012
Сообщений: 5,202
Записей в блоге: 2
16.08.2025, 20:14
Вот 3 последних ответа. Первый - человек впадает в амбицию и злобно тыкает Второй - упоминание о научной работе (видимо серьезной). Третий - это ж антипаттерн, мол, так вообще делать не нужно. В общем, что угодно - лишь бы не работать. Зачем? Зачем прилагать такие усилия чтобы отмазаться от написания несчастных 5 строчек кода? Может проще и лучше их взять да написать, а потом уже можно и покалякать "насколько это нужно/хорошо"?
0
фрилансер
 Аватар для Алексей1153
6504 / 5748 / 1134
Регистрация: 11.10.2019
Сообщений: 15,393
16.08.2025, 20:41
Цитата Сообщение от Igor3D Посмотреть сообщение
В общем, что угодно - лишь бы не работать
в общем, с тобой всё понятно
0
 Аватар для abit
870 / 529 / 149
Регистрация: 03.02.2013
Сообщений: 1,884
17.08.2025, 16:23
"рекурсивный мьютекс - это дикий антипаттерн"
А в плюсах традиция тащить антипттерны в std?
0
Нарушитель
Эксперт функциональных языков программированияЭксперт С++
6331 / 3063 / 1054
Регистрация: 01.06.2021
Сообщений: 11,713
17.08.2025, 16:54
abit, в std много чего есть такого, что не нужно использовать, например, https://en.cppreference.com/w/... /atoi.html

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

ещё есть goto

ещё есть using namespace std

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

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

много чего есть "интересного"
0
 Аватар для abit
870 / 529 / 149
Регистрация: 03.02.2013
Сообщений: 1,884
17.08.2025, 18:35
Зато полезные фичи из boost можно по 20 лет настаивать...
0
фрилансер
 Аватар для Алексей1153
6504 / 5748 / 1134
Регистрация: 11.10.2019
Сообщений: 15,393
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
Ответ Создать тему
Опции темы

Новые блоги и статьи
Программный домашний кинотеатр
russiannick 27.09.2026
Сподобился на программный домашний кинотеатр. В качестве ЯВУ по традиции выбрал js. В помощники взял Яндекс-Алису. Было создано три зала на разные интересы. исторические и ретро сериал Хичкок. . .
Беседа с ИИ о программистах, недопускающих к созданию и правке кода генеративные ИИ и причины этого
zorxor 21.09.2026
Раньше я радовался или получал некоторые эмоции, пусть небольшие, но всё же, от самого процесса написания кода, рекомпиляции и запуска, видя постепенное развитие программы и прочее. А теперь лень. . .
Мобильное приложение ColorStep
pavlinmavlin 17.09.2026
Реализовал приложение Красный, Зеленый, Синий в Unity3d + c#. Название изменил на ColorStep. Приложение прошло модерацию и теперь доступно для скачивания. Делал его сам, шаг за шагом — и вот,. . .
Запрет дублирования строк в табличной части
Maks 13.09.2026
Реализация из решения ниже выполнена на нетиповом справочнике "Нормы ТО" с табличной часть "Виды ТО", разработанного в КА2, со следующими реквизитами: - ВидТО (СправочникСсылка. ВидыТО); - ВидГСМ. . .
Скрипты Tampermonkey для CyberForum, ChatGPT, Claude и пр.
Jin X 06.09.2026
Скрипты Tampermonkey для CyberForum, ChatGPT, Claude и пр. Работая с форумом и нейросетями в браузере часто хочется что-то подкорректировать или добавить какого-то функционала. Ниже прикреплён. . .
Программа опроса у.з. расходомера SLS-720F
Argus19 02.09.2026
Программа опроса у. з. расходомера SLS-720F Программа опрашивает один раз в минуту три ультразвуковых расходомера SLS-720F через интерфейс RS-485 по протоколу Modbus RTU. Опрашиваются регистры. . .
Hyper-V: Компьютер должен поддерживать доверенный платформенный модуль 2.0.
Maks 31.08.2026
При установке Windows 11 на виртуальную машину Hyper-V 2-го поколения вылезла такая ошибка: Решение: в параметрах виртуальной машины, в разделе "Безопасность" (Security) активировать флаг. . .
Архитектура биовида Стива в Майнкрафте: Зачем бонобо кубический каннибализм
anaschu 30.08.2026
Кубический Вагинокапитализм в Minecraft: Математический инвариант ОДУ и рок Стивов-бонобо Главная задача разработанной «Модели Всего» — наглядно продемонстрировать наличие системной «судьбы». . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru