-41 / 49 / 5
Регистрация: 10.01.2017
Сообщений: 1,915

Как создать многопоточность

15.08.2019, 21:11. Показов 9044. Ответов 35
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Здравствуйте,

Пытаюсь хотя бы на самом простом уровне понять, как работает std thread, для этого сделал вот такую простенькую задачку:

То есть, имеется одномерный вектор с числами. Нужно простым перебором среди этого вектора найти нужно число, вот вроде как распределил эту задачу между 3мя потоками, то есть 1ый поток перебирает первую часть массива, 2ой - середину и третий - концовку, все работает, но...
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
void  find_chislo(vector<int>&Chisla_func, int Find_chislo_func, int chislo_cores_func, string &Result_func, int &counter_func)
{
 
    cout << this_thread::get_id() << " - i:" <<counter_func<< endl;
 
    int Part = Chisla_func.size() / chislo_cores_func;
 
    for (int i = counter_func*Part; i < counter_func*Part+Part; i++)
    {
        if (Chisla_func[i] == Find_chislo_func)
        {
            Result_func = to_string(i);
            cout << "нашел" << endl;
        }
    }
 
}
 
[B]int main()[/B]
{
    setlocale(LC_ALL, "russian");
 
    cout << this_thread::get_id() << " - main" << endl;
 
    int Find_chislo = 6799999;
    int chislo_cores = 3;
    string Result="нет";
 
    int counter;
 
    vector<int>Chisla;
    
    for (int i = 0; i < 10000000; i++)
    {
        Chisla.push_back(i);
    }
 
    counter = 0;
    thread potok1(find_chislo, ref(Chisla), Find_chislo, chislo_cores, ref(Result), ref(counter));
 
    int counter1 = 1;
    thread potok2(find_chislo, ref(Chisla), Find_chislo, chislo_cores, ref(Result), ref(counter1));
 
    int counter2 = 2;
    thread potok3(find_chislo, ref(Chisla), Find_chislo, chislo_cores, ref(Result), ref(counter2));
 
 
    potok1.join();
    potok2.join();
    potok3.join();
    
    cout << Result << endl;
Но, тут я, вручную прописал кол-во потоков и передал в поток функцию в работу, а хотелось бы динамически, так ка заранее код-во потоков ведь не известно, ну как то так хотелось бы:

C++
1
2
3
4
5
6
7
8
    for (int i = 0; i < chislo_cores; i++)
    {
        counter = i;
 
        thread potok_i(find_chislo, ref(Chisla), Find_chislo, chislo_cores, ref(Result), ref(counter));
    }
 
    potok_all.koin();
Но, реально не могу понять, возможно ли это и как.
0
IT_Exp
Эксперт
34794 / 4073 / 2104
Регистрация: 17.06.2006
Сообщений: 32,602
Блог
15.08.2019, 21:11
Ответы с готовыми решениями:

Как создать многопоточность
В сети гуглил, но так банального ответа для себя не нашёл, как размногопоточить приложение, в delphi делал так function getnumberbux:...

Как создать многопоточность?
Мне нужно организовать работу нескольких экземпляров webBrowser'a в разных потоках. Т.е. в webBrowser'е отображается страница, где есть...

Многопоточность - как создать динамический массив потоков
Привет всем:) Вот решил заняться многопоточность и,как и у всех,возникли проблемы. 1) как создать динамический массив потоков? Unit1 ...

35
6772 / 4565 / 1844
Регистрация: 07.05.2019
Сообщений: 13,726
19.08.2019, 14:13
Студворк — интернет-сервис помощи студентам
Цитата Сообщение от Optimus11 Посмотреть сообщение
А можно самому создать пул thread потоков за раз и потом их использовать, как хочешь ?
И async не надо тогда использовать будет.
Да, можно
0
Эксперт С++
 Аватар для hoggy
8973 / 4319 / 960
Регистрация: 15.11.2014
Сообщений: 9,760
19.08.2019, 14:54
Цитата Сообщение от oleg-m1973 Посмотреть сообщение
std::async - выполняет задачу на пуле потоков. Т.е., как правило, берёт уже созданный поток
откуда ты взял своё "т.е" ?

ты хотя б в документацию то заглядывал то?

std::launch::async a new thread is launched to execute the task asynchronously
std::launch::deferred the task is executed on the calling thread the first time its result is requested (lazy evaluation)
тоже самое, только по-русски:

launch::async – если передан этот флаг, то поведение async будет следующим: будет создан объект класса thread, с функцией и её аргументами в качестве аргументов нового потока. Т.е. async инкапсулирует создание потока, получение future и предоставляет однострочную запись для выполнения такого кода(скорее всего реализация будет использовать packaged_task, вместо простой передачи функции в поток, “под капотом”, но я не уверен)
launch::deferred – если передан этот флаг, то имя функции async становится несколько не логичным. Т.к. никакого асинхронного вызова не произойдёт. Вместо исполнения функции в новом потоке, она, вместе с аргументами, будет сохранена в future(еще одна особенность future), чтобы быть вызванными позже. Это позже наступит тогда, когда кто-либо вызовет метод get(или wait, но не wait_for!) на future, которое вернул async. При этот вызываемый объект выполнится в потоке, который вызывал get! Это поведение есть ни что иное, как отложенный вызов процедуры.
launch::async | launch::deferred - в этом случае будет выбрано одно из двух поведений описанных выше. Какое из двух? Неизвестно и зависит от имплементации.
Цитата Сообщение от oleg-m1973 Посмотреть сообщение
Для выполнения запросов от клиентов лучше использовать std::async
лучше использовать тред-пул.

который не имеет отношение ни к std::async,
ни к std::future.

Цитата Сообщение от oleg-m1973 Посмотреть сообщение
При запуске процесса создаётся пул потоков.
ты бредишь?
0
6772 / 4565 / 1844
Регистрация: 07.05.2019
Сообщений: 13,726
19.08.2019, 15:13
Цитата Сообщение от hoggy Посмотреть сообщение
откуда ты взял своё "т.е" ?
ты хотя б в документацию то заглядывал то?
Ты сам-то читаешь документацию?

The template function async runs the function f asynchronously (potentially in a separate thread which may be part of a thread pool) and returns a std::future that will eventually hold the result of that function call.
И посмотри реализацию std::async в майкрософте, так для общего развития.

Цитата Сообщение от hoggy Посмотреть сообщение
ты бредишь?
A pool object is a set of worker threads that can be used to perform work. Each process can create multiple isolated pools with different characteristics as necessary. There is also a default pool for each process.
https://docs.microsoft.com/en-... d-pool-api
1
Эксперт С++
 Аватар для hoggy
8973 / 4319 / 960
Регистрация: 15.11.2014
Сообщений: 9,760
19.08.2019, 15:54
Цитата Сообщение от oleg-m1973 Посмотреть сообщение
Ты сам-то читаешь документацию?
Цитата Сообщение от oleg-m1973 Посмотреть сообщение
И посмотри реализацию std::async в майкрософте, так для общего развития.
ты прав.

я недоглядел.
сейчас понял, что мои знания устарели.

что показал отладчик:
под капотом std::async (реализация от мелкомягких) - тред-пул.

если запустить одиночную задачу:

C++
1
2
3
4
5
6
7
8
9
10
11
int main()
{
        // ---- вот здесь в системе один единственный Main.Thread
        {
            auto f1 = std::async(foo);   //<--- создаётся новый тред. 
            f1.get();   
        }
        //<--- здесь объект фьючи уже не существует.
        // однако тредов по прежнему два.
        // созданный чуть выше тред не прекращает своё существование
}
соответственно:

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
int main()
{
        auto f1  = std::async(foo);
        auto f2  = std::async(foo);
        auto f3  = std::async(foo);
        auto f4  = std::async(foo);
        auto f5  = std::async(foo);
        auto f6  = std::async(foo);
        auto f7  = std::async(foo);
        auto f8  = std::async(foo);   // <--- у машинки 8мь ядер
        auto f9  = std::async(foo);
        auto f10 = std::async(foo);
 
        f1.get();
        f2.get();
        f3.get();
        f4.get();
        f5.get();
        f6.get();
        f7.get();
        f8.get();
        f9.get();
        f10.get();
}
несколько запусков - несколько результатов: от 4 и до 6ти тредов.
видимо, он там как то балансирует нагрузку.
потоки создает только при необходимости.

итого:
признаю.
насчет трел-пула ты был прав.
2
-41 / 49 / 5
Регистрация: 10.01.2017
Сообщений: 1,915
19.08.2019, 21:18  [ТС]
Подскажите пожалуйста, а как Вы проверяете, что создался thread и что он в итоге остался созданным после завершения ?

Добавлено через 1 час 39 минут
А в диспетчере задач чтоли ?
0
6772 / 4565 / 1844
Регистрация: 07.05.2019
Сообщений: 13,726
19.08.2019, 21:22
Цитата Сообщение от Optimus11 Посмотреть сообщение
А в диспетчере задач чтоли ?
Потоки можно посмотреть в process explorer https://docs.microsoft.com/en-... s-explorer
1
-41 / 49 / 5
Регистрация: 10.01.2017
Сообщений: 1,915
20.08.2019, 09:21  [ТС]
Подскажите пожалуйста, а почему так получаетcя, что каждая из 10 async создалась в одном и том же потоке, а не в разных ?

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
void foo()
{
cout<<"this_thread::get_id()<<endl;"
}
 
Int main()
{
 
for(int i=0; i<10; i++)
{
async(launch::async, foo)
}
 
}
0
6772 / 4565 / 1844
Регистрация: 07.05.2019
Сообщений: 13,726
20.08.2019, 09:29
Цитата Сообщение от Optimus11 Посмотреть сообщение
Подскажите пожалуйста, а почему так получаетcя, что каждая из 10 async создалась в одном и том же потоке, а не в разных ?
Потому что std::async возвращает std::future, которая в деструкторе ждёт завершения задачи.
Попробуй сделать
C++
1
2
3
        std::vector<std::future<void>> res;
        for (int i = 0; i < 10; i++)
            res.emplace_back(async(launch::async, foo));
1
Неэпический
 Аватар для Croessmah
18149 / 10731 / 2067
Регистрация: 27.09.2012
Сообщений: 27,035
Записей в блоге: 1
20.08.2019, 12:50
Optimus11, может всё-таки книжку?
1
-41 / 49 / 5
Регистрация: 10.01.2017
Сообщений: 1,915
20.08.2019, 19:36  [ТС]
Понял, придется купить
0
-41 / 49 / 5
Регистрация: 10.01.2017
Сообщений: 1,915
07.09.2019, 20:56  [ТС]
Здравствуйте,

Если создать сразу 10 - async(launch::async, Foo), то виндовс выделит под это дело с запасом 100 потоков. Потоки смотрю в диспетчере задач.
Если создать сразу 100 async, то винда выделяет сразу 500 потоков.
А вот если создать сразу 1000 async, то почему то виндовс более 500 потоков не создает. А почему ?

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
void Foo()
{
this_thread::sleep_for(chrono::milliseconds(10000)); // Задержка 10 сек
cout<<Создался поток:<<this_thread::get_id()<<endl;
}
 
 
int main()
{
    vector<future<void>>Vector_future;
 
    for (int i=0; i<10;i++)
    {
        Vector_future.emplace_back(async(launch::async, Foo);
    }
0
6772 / 4565 / 1844
Регистрация: 07.05.2019
Сообщений: 13,726
07.09.2019, 21:03
Цитата Сообщение от Optimus11 Посмотреть сообщение
Если создать сразу 10 - async(launch::async, Foo), то виндовс выделит под это дело с запасом 100 потоков. Потоки смотрю в диспетчере задач.
Если создать сразу 100 async, то винда выделяет сразу 500 потоков.
А вот если создать сразу 1000 async, то почему то виндовс более 500 потоков не создает. А почему ?
100 потоков - не знаю зачем, а 500 - это максимальное количество в пуле потоков, который по-умолчанию.
https://docs.microsoft.com/en-... read-pools
Do not queue too many items too quickly in a process with other components using the default thread pool. There is one default thread pool per process, including Svchost.exe. By default, each thread pool has a maximum of 500 worker threads. The thread pool attempts to create more worker threads when the number of worker threads in the ready/running state must be less than the number of processors.
1
-41 / 49 / 5
Регистрация: 10.01.2017
Сообщений: 1,915
09.09.2019, 21:24  [ТС]
Подскажите пожалуйста, вот нужно контролировать кол-во созданных и рабочих на данный момент потоков, что бы контролировать создание новых, то есть к примеру если на данный момент работает 100 потоков, то 101 поток создавать нельзя.
Вот только я не знаю, как это можно сделать специальными средствами и решил сделать самым простым способом, который пришел в голову, то есть просто создаем int переменную, передаем ее в функцию, которую необходимо запустить в отдельном потоке по ссылке, и сразу же с самого начало функции прибавляем 1, то есть значит, что минимум один поток начал свою работу, и так же, как только весь код-функции выполнен убавляем 1, значит поток закончил свою работу, а так как это все происходит по ссылке, то таким образом можно контролировать из основного потока реально кол-во работающих потоков, и если оно превысило определенную величину, в данном случае 100, то просто не создавать новых async, до тех порт пока кол-во потоков не будет менее 100.

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
void monitoring_thread(int &counter_func)
{
for(;;)
{
cout<<counter_func<<endl;  // сдесь просто выводим на консоль, чтобы и визуально еще можно было бы наблюдать, сколько потоков в работе на данный момент.
}
}
 
void foo(int &counter_func)
{
mutex.lock();
counter_func=counter_func+1;
mutex.unlock();
 
//Код функции...
 
mutex.lock();
counter_func=counter_func-1;
mutex.unlock();
}
 
 
 
int main()
{
int counter=0; 
 
thread mntr_thread(monitoring_thread, ref(counter));
 
 
vector<future<void>>Vector_foo;
for (;;)
        if(counter<100)
{
    {
        Vector_foo.emplace_back(async(launch::async, foo);
    }
}
 
}
Насколькл вообще так корректно делать ?
0
6772 / 4565 / 1844
Регистрация: 07.05.2019
Сообщений: 13,726
09.09.2019, 21:36
Цитата Сообщение от Optimus11 Посмотреть сообщение
Подскажите пожалуйста, вот нужно контролировать кол-во созданных и рабочих на данный момент потоков, что бы контролировать создание новых, то есть к примеру если на данный момент работает 100 потоков, то 101 поток создавать нельзя.
Ну, контролировать-то несложно. Увеличиваешь счётчик, std::atomic<size_t>, перед вызовом std::async, уменьшаешь при выходе из неё. Но ещё надо решить, что ты будешь делать, если поток создавать нельзя.
1
-41 / 49 / 5
Регистрация: 10.01.2017
Сообщений: 1,915
09.09.2019, 21:48  [ТС]
Цитата Сообщение от oleg-m1973 Посмотреть сообщение
Ну, контролировать-то несложно. Увеличиваешь счётчик, std::atomic<size_t>, перед вызовом std::async, уменьшаешь при выходе из неё. Но ещё надо решить, что ты будешь делать, если поток создавать нельзя.
Если поток создавать нельзя, просто буду пропускать цикл создания потока, пока условие для создания нового опять не восстановится.

А чем принципиально будет отличатся использования std::atomic от просто передачи int`а по ссылке в функию и так же увеличивать и уменьшать счетчик ?
0
6772 / 4565 / 1844
Регистрация: 07.05.2019
Сообщений: 13,726
09.09.2019, 22:43
Лучший ответ Сообщение было отмечено Optimus11 как решение

Решение

Цитата Сообщение от Optimus11 Посмотреть сообщение
Если поток создавать нельзя, просто буду пропускать цикл создания потока, пока условие для создания нового опять не восстановится.
Здесь не пропускать надо, а ждать с помощью std::conditon_variable, пока счётчик не станет меньше максимального значения.

Цитата Сообщение от Optimus11 Посмотреть сообщение
А чем принципиально будет отличатся использования std::atomic от просто передачи int`а по ссылке в функию и так же увеличивать и уменьшать счетчик ?
Потому что операция ++ для int не является атомарной. Т.е. её нельзя вызывать одновременно из разных потоков. Для std::atomic можно
1
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
BasicMan
Эксперт
29316 / 5623 / 2384
Регистрация: 17.02.2009
Сообщений: 30,364
Блог
09.09.2019, 22:43
Помогаю со студенческими работами здесь

Как создать многопоточность из одного асинхронного потока?
есть данная процедура: private async void button2_Click(object sender, EventArgs e) { foreach (var item in...

Многопоточность. Создать визуальный объект по завершению потока
По окончанию работы потока необходимо создавать на форме определенное количество TButton'ов, с определенными параметрами.. Как быть?...

Создать треугольник и заставить его крутиться используя многопоточность GUI
Создать треугольник получилось. Заставить прямоугольник крутиться получилось. А вот вместе сделать всё не получилось :( Помогите...

Создать приложение, которое использует многопоточность при своей работе с RichTextBox
Создать приложение, которое использует многопоточность при своей работе: обновляет содержимое многострочного редактора RichTextBox и...

Многопоточность, как?
Покажите как правильно реализовать, пробовал сам разобраться, мозгов нехватило. private: System::Void...


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

Или воспользуйтесь поиском по форуму:
36
Ответ Создать тему
Опции темы

Новые блоги и статьи
Debian 13: Установка Lazarus QT5
ВитГо 09.05.2026
Эта инструкция моя компиляция инструкций volvo https:/ / www. cyberforum. ru/ blogs/ 203668/ 10753. html и его же старой инструкции по установке Lazarus с gtk2. . .
Нейросеть на алгоритме "эстафета хвоста" как перспектива.
Hrethgir 06.05.2026
На десерт, когда запущу сервер. Статья тут https:/ / habr. com/ ru/ articles/ 1030914/ . Автор я сам, нейросеть только помогает в вопросах которые мне не известны - не знаю людей которые знали-бы. . .
Асинхронный приём данных из COM-порта
Argus19 01.05.2026
Асинхронный приём данных из COM-порта Купил на aliexpress термопринтер QR701. Он оказался странным. Поключил к Arduino Nano. Был очень удивлён. Наотрез отказывается печатать русские буквы. Чтобы. . .
попытка написать игровой сервер на C++
pyirrlicht 29.04.2026
попытка написать игровой сервер на плюсах с открытым бесконечным миром. возможно получится прикрутить интерпретатор питон для кастомизации игровой логики. что есть на текущий момент:. . .
Контроль уникальности выбранного документа-основания при изменении реквизита
Maks 28.04.2026
Алгоритм из решения ниже разработан на примере нетипового документа "ЗаявкаНаРемонтСпецтехники", разработанного в КА2. Задача: уведомлять пользователя, если указанная заявка (документ-основание). . .
Благородство как наказание
Maks 24.04.2026
У хорошего человека отношения с женщинами всегда складываются трудно. А я человек хороший. Заявляю без тени смущения, потому что гордиться тут нечем. От хорошего человека ждут соответствующего. . .
Валидация и контроль данных табличной части документа перед записью
Maks 22.04.2026
Алгоритм из решения ниже реализован на примере нетипового документа, разработанного в КА2. Задача: контроль и валидация данных табличной части документа перед записью с учетом регламента компании. . .
Отчёт о затраченных материалах за определенный период с макетом печатной формы
Maks 21.04.2026
Отчёт из решения ниже размещён в конфигурации КА2. Задача: разработка отчёта по затраченным материалам за определённый период, с возможностью вывода печатной формы отчёта с шапкой и подвалом. В. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru