Форум программистов, компьютерный форум, киберфорум
С++ для начинающих
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
 
Рейтинг 4.74/43: Рейтинг темы: голосов - 43, средняя оценка - 4.74
-41 / 49 / 5
Регистрация: 10.01.2017
Сообщений: 1,915

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

15.08.2019, 21:11. Показов 8917. Ответов 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,034
Записей в блоге: 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
Ответ Создать тему
Новые блоги и статьи
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. На борту пять. . .
Камера Toupcam IUA500KMA
Eddy_Em 12.02.2026
Т. к. у всяких "хикроботов" слишком уж мелкий пиксель, для подсмотра в ESPriF они вообще плохо годятся: уже 14 величину можно рассмотреть еле-еле лишь на экспозициях под 3 секунды (а то и больше),. . .
И ясному Солнцу
zbw 12.02.2026
И ясному Солнцу, и светлой Луне. В мире покоя нет и люди не могут жить в тишине. А жить им немного лет.
«Знание-Сила»
zbw 12.02.2026
«Знание-Сила» «Время-Деньги» «Деньги -Пуля»
SDL3 для Web (WebAssembly): Подключение Box2D v3, физика и отрисовка коллайдеров
8Observer8 12.02.2026
Содержание блога Box2D - это библиотека для 2D физики для анимаций и игр. С её помощью можно определять были ли коллизии между конкретными объектами и вызывать обработчики событий столкновения. . . .
SDL3 для Web (WebAssembly): Загрузка PNG с прозрачным фоном с помощью SDL_LoadPNG (без SDL3_image)
8Observer8 11.02.2026
Содержание блога Библиотека SDL3 содержит встроенные инструменты для базовой работы с изображениями - без использования библиотеки SDL3_image. Пошагово создадим проект для загрузки изображения. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru