Форум программистов, компьютерный форум, киберфорум
С++ для начинающих
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 4.89/9: Рейтинг темы: голосов - 9, средняя оценка - 4.89
0 / 0 / 0
Регистрация: 04.05.2023
Сообщений: 9

Пул потоков thread

09.05.2023, 14:26. Показов 2265. Ответов 14
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Здравствуйте.
Изучаю параллельное программирование. С огромным трудом мне дается пул потоков.
Решил попробовать написать пул потоков так как я его понимаю, самый простой.
Вопрос только один, можно ли это назвать пулом или это ничего общего с ним не имеет и я вообще не правильно мыслю?

!!!ОСТОРОЖНО!!!
В коде присутствуют артефакты в виде бесполезных переменных, кое что закомментировано, код не причесан, за это прошу меня извинить.

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
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
#include <iostream>
#include <thread>
#include <vector>
#include <mutex>
 
#include <functional>
#include <queue>
#include <windows.h>
#include <stdio.h>
using namespace std;
 
 
class thread_pool
{
    vector<thread> th;
    vector<bool> statusTH;
    unsigned int id;
    unsigned int countthreads;
    queue <function<void()>> qWork;
    atomic_bool done;
    bool run;
    mutex mtx;
    function<void()> task;
    void WORK(unsigned int i) // основная функция для получения и исполнения работы потоком
    {
        //Sleep(2000);
        while (!done)
        {
            if (run && getJob())
            {
                task();
            }
            else
            {
                run = false;
                statusTH[i] = (false);
                this_thread::yield();
                if (!done)
                {
                    cout << "ОЖИДАНИЕ -> " << this_thread::get_id() << endl;
                    SuspendThread(th[i].native_handle());
                } 
                //Sleep(1000);
            }
            
        }
 
 
    }
 
public:
    bool getJob() // метод проверяющий очередь работ, и если она не пустая извлекает из нее работу
    {
        lock_guard <mutex> lockG(mtx);
        if (!qWork.empty())
        {
            cout << "DONE1 -> " << this_thread::get_id() << "   " << qWork.size() << endl;
            task = move(qWork.front());
            //task = qWork.front();    <-Альтернатива
            qWork.pop();
            return true;
        }
        else
        {
            done = true; //при выполнении завершает все потоки, пул не переходит в состояние ожидания новых работ
            return false;
        }
    }
    thread_pool() // конструктор
    {
        run = false;
        countthreads = thread::hardware_concurrency();
        if (countthreads == 0)
        {
            countthreads = 1;
        }
        for (unsigned int i = 0; i < countthreads; i++)
        {
            th.push_back(thread(&thread_pool::WORK, this ,i));
            statusTH.push_back(true);
        }
    }
    ~thread_pool() //деструктор, в котором присоединяются потоки к меин потоку
    {
        done = false;
        cout << "Деструктор" <<  endl;
        for (unsigned int i = 0; i < countthreads; i++)
        {
            if (th[i].joinable())
            {
                th[i].join();
            }
        }
    }
    void AddWorkInQueue(function<void()> Fun) //метод для добавления работ в очередь
    {
        lock_guard <mutex> lockG(mtx);
        qWork.push(Fun);
    }
    void startJob()//метод для старта потоков в пуле, для обработки очереди работ
    {
        run = true;
        for (unsigned int i = 0; i < countthreads; i++)
        {
            if (!statusTH[i])
            {
                statusTH[i] = true;
                ResumeThread(th[i].native_handle());
            }
        }
    }
};
void DoWork() // простенькая функция, для тестов
{
    cout << "РАБОТА -> " << this_thread::get_id() << endl;
    //this_thread::sleep_for(chrono::milliseconds(100));
}
 
int main() {
    setlocale(LC_ALL, "Russian");
 
    thread_pool t1;
 
    Sleep(2000);
   
    for (int i = 0; i < 1000; i++)
    {
        t1.AddWorkInQueue(DoWork);
    }
    Sleep(2000);
    t1.startJob();
    return 0;
}
0
Programming
Эксперт
39485 / 9562 / 3019
Регистрация: 12.04.2006
Сообщений: 41,671
Блог
09.05.2023, 14:26
Ответы с готовыми решениями:

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

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

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

14
 Аватар для Наталья8
621 / 379 / 67
Регистрация: 09.03.2016
Сообщений: 4,075
09.05.2023, 15:17
Что то наворочено... Но оно не работает от слова вообще.
Может у меня конструктор не очень подходит.
У вас там ещё --- #include <atomic> нету....
Вы это на телефоне писали?
Я слышал, особо гениальные програмисты так делают.

Добавлено через 12 минут
Я почитал, здесь не всё однозначно, на разных IDE...

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
class thread_pool
{
    vector<thread> th;
    vector<bool> statusTH;
    unsigned int id;
    unsigned int countthreads;
    queue <function<void()>> qWork;
//  Я хочу использовать, std::atomic_boolпотому что хочу иметь логическое значение,
//  к которому должны обращаться разные потоки.
    //atomic_bool done;
    atomic<bool>done;
    bool run;
    mutex mtx;
Добавлено через 41 секунду
https://stackoverflow.com/ques... tomic-bool
1
 Аватар для Наталья8
621 / 379 / 67
Регистрация: 09.03.2016
Сообщений: 4,075
09.05.2023, 15:21
0
0 / 0 / 0
Регистрация: 04.05.2023
Сообщений: 9
10.05.2023, 04:23  [ТС]
Поправил код, убрал все что не важно. Код писал на настоящем компьютере, но своими руками.
Код у меня как и исходный компилируется без ошибок, использую VS 2022. Проверил в онлайн компиляторе onlinegdb.com. Пришлось убрать и windows.h и добавить atomic, чтобы онлайн компилятор его переварил. Онлайн компилятор ID потока както не так показывает.
Наталья8 использовал atomic_bool так как вычитал в книге что это альтернатива atomic<bool>.
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
100
101
#include <iostream>
#include <thread>
#include <vector>
#include <mutex>
 
#include <functional>
#include <queue>
//#include <windows.h>
#include <atomic>
#include <stdio.h>
using namespace std;
 
 
class thread_pool
{
    vector<thread> th;
    unsigned int countthreads;
    queue <function<void()>> qWork;
    atomic<bool> done;
    mutex mtx;
    function<void()> task;
    void WORK(unsigned int i) // основная функция для получения и исполнения работы потоком
    {
        while (!done)
        {
            if (getJob())
            {
                task();
            }
            else
            {
                this_thread::sleep_for(chrono::milliseconds(1000));
                this_thread::yield();
            }
        }
    }
 
public:
    bool getJob() // метод проверяющий очередь работ, и если она не пустая извлекает из нее работу
    {
        lock_guard <mutex> lockG(mtx);
        if (!qWork.empty())
        {
            cout << "DONE1 -> " << this_thread::get_id() << "   " << qWork.size() << endl;
            task = move(qWork.front());
            qWork.pop();
            return true;
        }
        else
        {
            done = true; //при выполнении завершает все потоки, пул не переходит в состояние ожидания новых работ
            return false;
        }
    }
    thread_pool() // конструктор
    {
        countthreads = thread::hardware_concurrency();
        if (countthreads == 0)
        {
            countthreads = 1;
        }
        for (unsigned int i = 0; i < countthreads; i++)
        {
            th.push_back(thread(&thread_pool::WORK, this, i));
        }
    }
    ~thread_pool() //деструктор, в котором присоединяются потоки к меин потоку
    {
        done = false;
        for (unsigned int i = 0; i < countthreads; i++)
        {
            if (th[i].joinable())
            {
                th[i].join();
            }
        }
    }
    void AddWorkInQueue(function<void()> Fun) //метод для добавления работ в очередь
    {
        lock_guard <mutex> lockG(mtx);
        qWork.push(Fun);
    }
};
void DoWork() // простенькая функция, для тестов
{
    cout << "РАБОТА -> " << this_thread::get_id() << endl;
    this_thread::sleep_for(chrono::milliseconds(100));
}
 
int main() {
    setlocale(LC_ALL, "Russian");
 
    thread_pool t1;
    //Sleep(2000);
 
    for (int i = 0; i < 100; i++)
    {
        t1.AddWorkInQueue(DoWork);
    }
    return 0;
}
Миниатюры
Пул потоков thread  
0
 Аватар для Наталья8
621 / 379 / 67
Регистрация: 09.03.2016
Сообщений: 4,075
10.05.2023, 13:28
Компилиться. Что то выводит. (А чё это,)

0
 Аватар для Наталья8
621 / 379 / 67
Регистрация: 09.03.2016
Сообщений: 4,075
10.05.2023, 15:24
У меня MSVS 2013.
Может работать не правильно...

Добавлено через 1 час 51 минуту
Примерчик попроще, для разнообразия.
https://cplusplus.com/referenc... ead/yield/

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
// this_thread::yield example
#include <iostream>       // std::cout
#include <thread>         // std::thread, std::this_thread::yield
#include <atomic>         // std::atomic
 
std::atomic<bool> ready(false);
 
void count1m(int id) {
    while (!ready) std::this_thread::yield(); // подождите, пока main() не будет готов...(ждать)
        
for (volatile// компилятор не будет оптимизировать эту переменную
        int i = 0; i<10000000; ++i) {}
    std::cout << id<< " *";
}
 
 
 
//============================
int main()
{
    std::thread threads[10];
    std::cout << "race of 10 threads that count to 1 million:\n";
    for (int i = 0; i<10; ++i) threads[i] = std::thread(count1m, i);// Десять потоков делает
    ready = true;               // go!
    
    for (auto& th : threads) th.join();//Пробка <=============
    std::cout << '\n';
 
    getchar();
    return 0;
}
У меня работает...

Добавлено через 2 минуты
Была вот такая тема....
И что то толку с неё ноль...
std::thread - как запустить поток отложенно?
0
267 / 199 / 30
Регистрация: 26.11.2022
Сообщений: 869
10.05.2023, 15:48
тест сделайте нормальный - чтоб накладные расходы показал
0
0 / 0 / 0
Регистрация: 04.05.2023
Сообщений: 9
10.05.2023, 16:03  [ТС]
Наталья8 и Aledveu, вопрос у меня только один, можно ли дать точное определение тому коду который я написал, а именно является ли данное творчество пулом потоков.
Это мне нужно для общего понимания, я понимаю что если это и пул то очень ограниченный и не казистый. Дальше я его буду доводить до ума, важно, на данном этапе убедиться что направление правельное.
0
 Аватар для zayats80888
6352 / 3523 / 1428
Регистрация: 07.02.2019
Сообщений: 8,995
10.05.2023, 16:12
Цитата Сообщение от Klerc Посмотреть сообщение
а именно является ли данное творчество пулом потоков.
То, что в посте #4, можно так назвать.
Цитата Сообщение от Klerc Посмотреть сообщение
Дальше я его буду доводить до ума, важно, на данном этапе убедиться что направление правельное.
Направление правильное.
В первую очередь нужно избавиться от UB:
Цитата Сообщение от Klerc Посмотреть сообщение
function<void()> task;
Это разделяемое состояние с не синхронизированным доступом. От него нужно вообще избавится, сделать task локальным для каждого потока, не нужно оно как член класса.
1
0 / 0 / 0
Регистрация: 04.05.2023
Сообщений: 9
10.05.2023, 16:36  [ТС]
zayats80888 отлично.Насчёт task я так понял что потоки могут одновременно получить к нему доступ, тем самым исказить результат?
То есть когда поток выбрал из очереди задачу и вернулся обратно в цикл while, то следующий поток может заменить задачу следующей в очереди, ещё до выполнения предыдущим потоком?
0
 Аватар для zayats80888
6352 / 3523 / 1428
Регистрация: 07.02.2019
Сообщений: 8,995
10.05.2023, 16:39
Цитата Сообщение от Klerc Посмотреть сообщение
Насчёт task я так понял что потоки могут одновременно получить к нему доступ, тем самым исказить результат?
Именно так. Зачем вообще было делать его общим для всех потоков? В твоей реализации каждый поток выполняет свою задачу.
1
0 / 0 / 0
Регистрация: 04.05.2023
Сообщений: 9
10.05.2023, 16:47  [ТС]
Это одголоски от первых попыток, в первых моих набросках я мьютексом закрывал весь цикл. Про таск вообще как-то не подумал, ладно я с этим разберусь, спасибо за помощь.
А ещё вопрос, а если я всё-таки буду останавливать потоки, если им нечего делать, методом SuspendThread, это будет приемлемо? А чтобы их присоединить при уничтожении пула, я в деструкторе их опять буду запускать, чтоб они завершили цикл и выходили из него
0
 Аватар для zayats80888
6352 / 3523 / 1428
Регистрация: 07.02.2019
Сообщений: 8,995
10.05.2023, 16:51
Цитата Сообщение от Klerc Посмотреть сообщение
А ещё вопрос, а если я всё-таки буду останавливать потоки, если им нечего делать, методом SuspendThread, это будет приемлемо? А чтобы их присоединить при уничтожении пула, я в деструкторе их опять буду запускать, чтоб они завершили цикл и выходили из него
А кто тогда будет работу выполнять, если ты их все усыпишь до вызова деструтора?
В любом случае, нет необходимости использовать системное API явно, т.к. в стандартной библиотеке есть средства для "усыпления и пробуждения" потоков с помощью std::condition_variable.
1
0 / 0 / 0
Регистрация: 04.05.2023
Сообщений: 9
10.05.2023, 17:09  [ТС]
Хорошо, изучу. Я хотел написать пул который бы создавался в самом начале работы программы, при поступлении задач выполнял их, затем возвращался опять в состояние ожидания новых задач, а не крутил бы цикл, тем самым нагружая процессор
0
10.05.2023, 18:17

Не по теме:

Цитата Сообщение от Klerc Посмотреть сообщение
можно ли дать точное определение тому коду который я написал
Всё нормально, только сдаёться мне, что от разбора вашего кода, мне пользы не будет....

Добавлено через 5 минут
Я могу и не такое выставить. Только читать ни кто не будет...

0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
inter-admin
Эксперт
29715 / 6470 / 2152
Регистрация: 06.03.2009
Сообщений: 28,500
Блог
10.05.2023, 18:17
Помогаю со студенческими работами здесь

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

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

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

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

Массив потоков <thread>
Последний раз потоки писал на C под Linux. И там прокатывала такая штука thread a; for(int i=0;i&lt;n;i++) a_create(тряляля); ...


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

Или воспользуйтесь поиском по форуму:
15
Ответ Создать тему
Новые блоги и статьи
Уведомление о неверно выбранном значении справочника
Maks 06.04.2026
Алгоритм из решения ниже реализован на примере нетипового документа "НарядПутевка", разработанного в конфигурации КА2. Задача: уведомлять пользователя, если в документе выбран неверный склад. . .
Установка Qt Creator для C и C++: ставим среду, CMake и MinGW без фреймворка Qt
8Observer8 05.04.2026
Среду разработки Qt Creator можно установить без фреймворка Qt. Есть отдельный репозиторий для этой среды: https:/ / github. com/ qt-creator/ qt-creator, где можно скачать установщик, на вкладке Releases:. . .
AkelPad-скрипты, структуры, и немного лирики..
testuser2 05.04.2026
Такая программа, как AkelPad существует уже давно, и также давно существуют скрипты под нее. Тем не менее, прога живет, периодически что-то не спеша дополняется, улучшается. Что меня в первую очередь. . .
Отображение реквизитов в документе по условию и контроль их заполнения
Maks 04.04.2026
Алгоритм из решения ниже реализован на примере нетипового документа "ПланированиеСпецтехники", разработанного в конфигурации КА2. Данный документ берёт данные из другого нетипового документа. . .
Фото всей Земли с борта корабля Orion миссии Artemis II
kumehtar 04.04.2026
Это первое подобное фото сделанное человеком за 50 лет. Снимок называют новым вариантом легендарной фотографии «The Blue Marble» 1972 года, сделанной с борта корабля «Аполлон-17». Новое фото. . .
Вывод диалогового окна перед закрытием, если документ не проведён
Maks 04.04.2026
Алгоритм из решения ниже реализован на примере нетипового документа "СписаниеМатериалов", разработанного в конфигурации КА2. Задача: реализовать программный контроль на предмет проведения документа. . .
Программный контроль заполнения реквизитов табличной части документа
Maks 02.04.2026
Алгоритм из решения ниже реализован на примере нетипового документа "СписаниеМатериалов", разработанного в конфигурации КА2. Задача: 1. Реализовать контроль заполнения реквизита. . .
wmic не является внутренней или внешней командой
Maks 02.04.2026
Решение: DISM / Online / Add-Capability / CapabilityName:WMIC~~~~ Отсюда: https:/ / winitpro. ru/ index. php/ 2025/ 02/ 14/ komanda-wmic-ne-naydena/
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru