Форум программистов, компьютерный форум, киберфорум
С++ для начинающих
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск  
 
 
Рейтинг 4.83/6: Рейтинг темы: голосов - 6, средняя оценка - 4.83
242 / 208 / 36
Регистрация: 19.02.2021
Сообщений: 1,431

Пул потоков - непонятки

22.10.2023, 18:13. Показов 1568. Ответов 25
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Здравствуйте!
Для своей демки честно стырил в инете вариант реализации пула потоков.
Посмотрел его, поковырял - вроде, все понятно, но все же не все)))
Вот его реализация:
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
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
#include <iostream>
#include <queue>
#include <thread>
#include <chrono>
#include <mutex>
#include <future>
#include <unordered_set>
#include <atomic>
 
#include <vector>
#include <chrono>
 
// C++ 14
class thread_pool {
public:
    thread_pool(uint32_t num_threads) {
        threads.reserve(num_threads);
        for (uint32_t i = 0; i < num_threads; ++i) {
            threads.emplace_back(&thread_pool::run, this);
        }
    }
 
    template <typename Func, typename ...Args>
    int64_t add_task(const Func& task_func, Args&&... args) {
        int64_t task_idx = last_idx++;
 
        std::lock_guard<std::mutex> q_lock(q_mtx);
        q.emplace(std::async(std::launch::deferred, task_func, args...), task_idx);
        q_cv.notify_one();
        return task_idx;
    }
 
    void wait(int64_t task_id) {
        std::unique_lock<std::mutex> lock(completed_task_ids_mtx);
        completed_task_ids_cv.wait(lock, [this, task_id]()->bool {
            return completed_task_ids.find(task_id) != completed_task_ids.end();
            });
    }
 
    void wait_all() {
        std::unique_lock<std::mutex> lock(q_mtx);
        completed_task_ids_cv.wait(lock, [this]()->bool {
            std::lock_guard<std::mutex> task_lock(completed_task_ids_mtx);
            return q.empty() && last_idx == completed_task_ids.size();
            });
    }
 
    bool calculated(int64_t task_id) {
        std::lock_guard<std::mutex> lock(completed_task_ids_mtx);
        if (completed_task_ids.find(task_id) != completed_task_ids.end()) {
            return true;
        }
        return false;
    }
 
    ~thread_pool() {
        quite = true;
        for (uint32_t i = 0; i < threads.size(); ++i) {
            q_cv.notify_all();
            threads[i].join();
        }
    }
 
private:
 
    void run() {
        while (!quite) {
            std::unique_lock<std::mutex> lock(q_mtx);
            q_cv.wait(lock, [this]()->bool { return !q.empty() || quite; });
 
            if (!q.empty()) {
                auto elem = std::move(q.front());
                q.pop();
                lock.unlock();
 
                elem.first.get();
 
                std::lock_guard<std::mutex> lock(completed_task_ids_mtx);
                completed_task_ids.insert(elem.second);
 
                completed_task_ids_cv.notify_all();
            }
        }
    }
 
    std::queue<std::pair<std::future<void>, int64_t>> q; // очередь задач - хранит функцию(задачу), которую нужно исполнить и номер данной задачи
    std::mutex q_mtx;
    std::condition_variable q_cv;
 
    std::unordered_set<int64_t> completed_task_ids;      // помещаем в данный контейнер исполненные задачи
    std::condition_variable completed_task_ids_cv;
    std::mutex completed_task_ids_mtx;
 
    std::vector<std::thread> threads;
 
 
    std::atomic<bool> quite{ false };                    // флаг завершения работы thread_pool
    std::atomic<int64_t> last_idx = 0;                   // переменная хранящая id который будет выдан следующей задаче
};
Меня интересует функция
C++
1
2
3
4
5
6
7
    void wait_all() {
        std::unique_lock<std::mutex> lock(q_mtx);
        completed_task_ids_cv.wait(lock, [this]()->bool {
            std::lock_guard<std::mutex> task_lock(completed_task_ids_mtx);
            return q.empty() && last_idx == completed_task_ids.size();
            });
    }
Во-первых, моя демка в ней "зависает", во-вторых, я не совсем понимаю, как работает conditional_variable completed_task_ids_cv
Честно пытался читать в инете, но недопонимаю.
Lock, как я понимаю, это мьютекс(q_mtx), который предварительно захвачен.
completed_task_ids_cv.wait() должен этот мьютекс освободить, если лямбда вернет true. Правильно?
Как выполняется тело лямбды? Крутится постоянно, пока не выполниться условие? Или как?
У меня "висит" на строке
std::unique_lock<std::mutex> lock(q_mtx) - такое впечатление, что wait_all() вызвался повторно, до освобождения мьютекса q_mtx и не может его захватить.
Но по стеку видно, что повторного вызова нет.
Может я чего-то недопонимаю?

По алгоритму демки, я "подкидываю" задачи в пул потоков, в месте, где нужны результаты, жду при помощи вот этой вот функции wait_all()
Подавляющее количество времени оно все работает. Но иногда, очень редко, "зависает" в этой функции на этой строке.

Демку могу приаттачить, но она без wxWidgets не соберется.
0
IT_Exp
Эксперт
34794 / 4073 / 2104
Регистрация: 17.06.2006
Сообщений: 32,602
Блог
22.10.2023, 18:13
Ответы с готовыми решениями:

Есть ли в C++ пул потоков
Перерыл много ссылок и не мог найти есть ли в с++ пул потоков,все источники указывают на с# ThreadPol,у меня курсовая пул потоков а...

Пул потоков thread
Здравствуйте. Изучаю параллельное программирование. С огромным трудом мне дается пул потоков. Решил попробовать написать пул потоков...

Пул потоков с семафорами
Задача:написать свой пуль потоков Написал вот такой код #include &lt;windows.h&gt; #include &quot;Worker.h&quot; #include&lt;list&gt; ...

25
274 / 206 / 30
Регистрация: 26.11.2022
Сообщений: 887
24.10.2023, 12:25
Студворк — интернет-сервис помощи студентам
признак простоя пула - это не пустота в списке задач.
Я у себя в пуле потоков делал два атомарных счётчика - количество работающих потоков в пуле и счётчик активных потоков.
Перед вызовом функции задания из очереди счётчик увеличивался а после возврата - уменьшался.

И для завершения пула потоков вначале блокировалось добавление новых заданий в очередь, а если оно происходило - то задания выполнялись сразу на мете. Потом ожидалось опустошение очереди, потом ожидалось обнуление счётчика.
решение имеет недостатки но надёжное.
0
242 / 208 / 36
Регистрация: 19.02.2021
Сообщений: 1,431
24.10.2023, 16:05  [ТС]
Цитата Сообщение от Aledveu Посмотреть сообщение
признак простоя пула - это не пустота в списке задач.
Я не список задач имел ввиду. Понятно, что список может быть пуст, но какие-то задачи еще выполняются.
Я имел ввиду список задач, выполняющихся в текущий момент.

Цитата Сообщение от Aledveu Посмотреть сообщение
Я у себя в пуле потоков делал два атомарных счётчика - количество работающих потоков в пуле и счётчик активных потоков.
Перед вызовом функции задания из очереди счётчик увеличивался а после возврата - уменьшался.
Вот это больше подходит.
Но можно вообще одним счетчиком обойтись - количеством потоков, работающих в текущий момент + очередь ожидающих задач.
0
242 / 208 / 36
Регистрация: 19.02.2021
Сообщений: 1,431
25.10.2023, 15:37  [ТС]
Все-таки не получется разобраться. Разьясните, пожалуйста, этот момент с contitional_variable:
1. В функцию wait() передается захваченный мьютекс и некое условие.
2. В функции wait() contitional_variable освобождает этот мьютекс и ждет? Или проверяет условие? Что там внутри происходит?
В документации сказано, что из какого-то другого потока должен быть послан сигнал notify_one() или notify_all() этой же contitional_variable для того, чтобы проинформировать ее, что условие поменялось.
Правильно ли я понимаю, что contitional_variable не проверяет это условие постоянно, а ждет сигнала и только после него проверяет, и если оно выполнено - захватывает мьютекс и выходит из wait()
Если это так - тогда зачем вообще это условие, когда все равно нужен внешний сигнал?
0
19501 / 10106 / 2461
Регистрация: 30.01.2014
Сообщений: 17,825
25.10.2023, 17:14
Цитата Сообщение от Constcat Посмотреть сообщение
В функции wait() contitional_variable освобождает этот мьютекс и ждет?
Да.

Цитата Сообщение от Constcat Посмотреть сообщение
Или проверяет условие?
Проверяет после получения сигнала.

Цитата Сообщение от Constcat Посмотреть сообщение
Если это так - тогда зачем вообще это условие, когда все равно нужен внешний сигнал?
Сигнал пробуждает от ожидания, но из ожидания можно выйти и самопроизвольно по каким-либо системным причинам, поэтому условие нужно, чтобы точно определить корректность пробуждения.
1
242 / 208 / 36
Регистрация: 19.02.2021
Сообщений: 1,431
25.10.2023, 18:46  [ТС]
Цитата Сообщение от DrOffset Посмотреть сообщение
Сигнал пробуждает от ожидания, но из ожидания можно выйти и самопроизвольно по каким-либо системным причинам, поэтому условие нужно, чтобы точно определить корректность пробуждения.
Получается, что wait() ждет сигнала, даже если условие изначально выполнено?
0
19501 / 10106 / 2461
Регистрация: 30.01.2014
Сообщений: 17,825
25.10.2023, 19:37
Constcat, не, первый раз условие проверяется до ожидания. Так что если оно уже выполнено, то ожидания не будет.
1
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
BasicMan
Эксперт
29316 / 5623 / 2384
Регистрация: 17.02.2009
Сообщений: 30,364
Блог
25.10.2023, 19:37

Квази пул потоков
Здравствуйте, Подскажите, вот попытался сделать условно &quot;макетную плату&quot; пула потоков на простых элементах, естественно использовать в...

Передача функции с параметрами в пул потоков
Здравствуйте, имеется многопоточный producer consumer. Он должен вызывать функцию ProcessRequest с параметром полученным из GetRequest. К...

Пул потоков на основе boost::lockfree::queue
В книге &quot;Энтони Уильямс - Параллельное программирование на С++ в действии&quot; обсуждается пул потоков на основе самописной потокобезопасной...

Реализовать пул потоков, в который можно помещать функцию
не могу реализовать как в книге главу 9 пул потоков который,в который можно помещать функцию что бы она возвращала значение вот код который...

Можно ли сделать доступным для всех классов пул потоков?
У меня есть пул потоков который я хочу сделать доступным для всех чтолибоделающих классов. Есть класс основной Base и два класса которые...


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

Или воспользуйтесь поиском по форуму:
26
Ответ Создать тему
Новые блоги и статьи
Был праздник вчера, а я и не знал.
kumehtar 28.07.2026
27. 07. 2026г. Intel Core 2 Duo исполнилось 20 лет Новости компьютерного мира и их обсуждение (4) Салют, шампанское, овации! :drink:
Нейтральные знания, чистый код - бла-бла-бла-бла, на самом деле кликбейт и самореклама, плагиат, и вот почему
Hrethgir 27.07.2026
То-есть отклонение такой публикации говорит само за себя, и пусть только возьмут на вооружение после отклонения публикации - это будет чистейшим актом плагиата. Отклонял Хабр. Дословно, отклонённая. . .
тв 16 бой ии
anaschu 27.07.2026
Великий Перелом ИИ: Как уравнения ОДУ Radau дожали цензурные фильтры Алисы Фиксируем в мемофонде Теории Всего беспрецедентный факт в истории ИИ-зондирования. В затяжном многораундовом. . .
мв 15. непроверенное, возможно, глюк
anaschu 27.07.2026
НАУЧНО-АНАЛИТИЧЕСКИЙ ОТЧЕТ. РАЗДЕЛ 1. 1: «НАУКА» (РАСШИРЕННАЯ СТЕХИОМЕТРИЧЕСКАЯ И ГЕНЕТИЧЕСКАЯ ВЕРСИЯ)Тема: Теоретическое обоснование инвариантности 19-мерного тензорного ядра непрерывных ОДУ и. . .
Очистка реквизитов и табличных частей документа при копировании (вариант 2)
Maks 26.07.2026
Алгоритм из решения ниже разработан на примере нетипового документа "ЗаявкаНаРаботу", разработанного в КА2. Задача: Заменить алгоритм запрета копирования документов для сотрудников с ролью "Стажер",. . .
Доктрина интенционального знания - Доктрина для портала "Срез".
Hrethgir 25.07.2026
Может найдётся кто захочет оценить доктрину. . . Написания правил участия для меня роскошь, требующая лимита времени, поэтому все сообщения не прошедшие модерацию будут видны только участникам портала,. . .
сукцессия 44. Решил подать на припринт в межународные сервисы препринтов. Но нужно одобрение от ученых
anaschu 25.07.2026
Английский вариант. Пока кто то не одобрит мою личность, мне не получиться это опубликовать на препринте. Но заявку на публикацию статьи я сегодня подам.
сукцессия 43. Вторая научная статья за месяц- прайминг и гатгил
anaschu 25.07.2026
две стороны одной монеты
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru