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

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

15.08.2019, 21:11. Показов 8915. Ответов 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
2784 / 1937 / 570
Регистрация: 05.06.2014
Сообщений: 5,602
15.08.2019, 21:43
Ну так сложите все треды в массив какого вам надо размера.
1
Неэпический
 Аватар для Croessmah
18148 / 10732 / 2067
Регистрация: 27.09.2012
Сообщений: 27,031
Записей в блоге: 1
15.08.2019, 22:03
Цитата Сообщение от Optimus11 Посмотреть сообщение
Но, реально не могу понять, возможно ли это и как.
можете посмотреть идею здесь: Многопоточный проход по матрице
2
6772 / 4565 / 1844
Регистрация: 07.05.2019
Сообщений: 13,726
16.08.2019, 09:13
Лучший ответ Сообщение было отмечено Optimus11 как решение

Решение

Цитата Сообщение от Optimus11 Посмотреть сообщение
Но, тут я, вручную прописал кол-во потоков и передал в поток функцию в работу, а хотелось бы динамически, так ка заранее код-во потоков ведь не известно, ну как то так хотелось бы:
Во первых, сделай массив потоков
C++
1
2
3
std::vector<std::thread> threads;
for (size_t i = std::thread::hardware_concurrency(); i > 0; --i)
         threads.emplace_back(find_chislo..................
C++
1
2
for (auto &thread: threads)
     thread.join();
Во-вторых, ты вычисляешь размер блока как Chisla_func.size() / chislo_cores_func. А если размер массива не кратен количеству потоков? Здесь надо так
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
void  find_chislo(const int *p, size_t n, string &Result_func) {......................
 
..............................
 
const int *p = Chisla.data();
size_t sz = Chisla.size();
for (size_t i = std::thread::hardware_concurrency(); i > 0; --i)
{
    const size_t n = sz / i;
    threads.emplace_back(find_chislo, p, n, std::ref(Result));
    p += n;
    sz -= n;
}
1
-41 / 49 / 5
Регистрация: 10.01.2017
Сообщений: 1,915
16.08.2019, 13:27  [ТС]
Спасибо! Работает.

Позвольте пожалуйста несколько общих вопросов:
1)А что происходит с потоком, когда весь код внутри потока выполнен или когда поток достиг join ? Он как то удаляется ?
2)возможно ли сделать, чтобы к примеру, вот есть три потока к примеру, вме они заняты поиском числа в одном и том же массиве и вот предположи во 2ом потоке нужное значение найдено и он завершил свою работу, но 1ый и 3ий еще продолжают искать и тратить время процессора, можно ли как то принудительно остановить работу нужных потоков ?
0
6772 / 4565 / 1844
Регистрация: 07.05.2019
Сообщений: 13,726
16.08.2019, 13:35
Цитата Сообщение от Optimus11 Посмотреть сообщение
1)А что происходит с потоком, когда весь код внутри потока выполнен или когда поток достиг join ? Он как то удаляется ?
В windows - поток не удалится, пока ты не сделаешь ::CloseHande.
std::thread скорее всего также - ничего не удалится, пока не будет удалён объект, т.е. пока не будет вызван деструктор std::thread

Добавлено через 1 минуту
Цитата Сообщение от Optimus11 Посмотреть сообщение
2)возможно ли сделать, чтобы к примеру, вот есть три потока к примеру, вме они заняты поиском числа в одном и том же массиве и вот предположи во 2ом потоке нужное значение найдено и он завершил свою работу, но 1ый и 3ий еще продолжают искать и тратить время процессора, можно ли как то принудительно остановить работу нужных потоков ?
Сделай
C++
1
2
3
4
5
6
7
8
9
10
11
12
volatile bool stop = false;
 
    for (int i = counter_func*Part; !stop && i < counter_func*Part+Part; i++)
    {
        if (Chisla_func[i] == Find_chislo_func)
        {
stop = true;
            Result_func = to_string(i);
            cout << "нашел" << endl;
 
        }
    }
1
Эксперт С++
 Аватар для hoggy
8973 / 4319 / 960
Регистрация: 15.11.2014
Сообщений: 9,760
16.08.2019, 14:01
Лучший ответ Сообщение было отмечено Optimus11 как решение

Решение

Цитата Сообщение от Optimus11 Посмотреть сообщение
А что происходит с потоком, когда весь код внутри потока выполнен или когда поток достиг join ? Он как то удаляется ?
с точки зрения юзерского кода, потока больше не существует.

кто и как подчищает - не юзерского ума дела.
за это отвечает std::thread в связке с API системы.
и что именно он делает - не регламентируется.

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

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include <iostream>
#include <thread>
 
void work()
{
    std::cout << "work...\n";
}
 
int main()
{
    std::thread worker(work);
    worker.join();  // <--- завершился
    
    worker = std::thread(work); // <--- запуск нового потока
    worker.join();
}
Цитата Сообщение от Optimus11 Посмотреть сообщение
можно ли как то принудительно остановить работу нужных потоков ?
технически можно.
можно вообще получить нативный хэндл потока std::thread::native_handle
и делать с тредом всё, что только позволяет апи системы.

в Windows можно убить поток например:

однако на практике так никто не делает.
в моральной программе, которую изготовил моральный программист,
поток должен (обязан!) корректно завершиться.

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

то бишь, поток сделал какую то очередную порцию работы,
и смотрит: а не получен ли уже сигнал об остановке?
нет - работает дальше. да - сворачивает лавочку.

для таких простых случаев как у тебя,
человечество изобрело std::atomic_bool

https://rextester.com/UBAKL42914

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
#include <iostream>
#include <atomic>
#include <chrono>
#include <thread>
 
std::atomic_bool stop;
 
void work()
{
    while(!stop)
    {
        std::cout << "thread: делаю вид, что работаю...\n";
        std::this_thread::sleep_for(
            std::chrono::seconds(1)
        );
    }
    std::cout << "thread: рабочий день закончился. я пошёль домой\n";
    
}
 
int main()
{
    std::cout << "main: запуск!\n";
    
    std::thread worker(work);
    std::this_thread::sleep_for(
        std::chrono::seconds(3)
    );
    std::cout << "main: сигнал об остановке\n";
    std::cout << "main: ожидаю завершения работы треда\n";
    stop = true;
    worker.join();
    
    std::cout << "main: thread завершился. конец программы\n";
}
output:
Code
1
2
3
4
5
6
7
8
9
main: запуск!
thread: делаю вид, что работаю...
thread: делаю вид, что работаю...
thread: делаю вид, что работаю...
thread: делаю вид, что работаю...
main: сигнал об остановке
main: ожидаю завершения работы треда
thread: рабочий день закончился. я пошёль домой
main: thread завершился. конец программы
1
-41 / 49 / 5
Регистрация: 10.01.2017
Сообщений: 1,915
16.08.2019, 15:55  [ТС]
Спасибо!!

Подсажите:
C++
1
2
3
4
5
std::thread worker(work);
    worker.join();  // <--- завершился
    
worker = std::thread(work); // ТАКИМ образом создается новый поток или ПЕРЕиспользуется уже старый ?
    worker.join();
0
6772 / 4565 / 1844
Регистрация: 07.05.2019
Сообщений: 13,726
16.08.2019, 16:04
Цитата Сообщение от Optimus11 Посмотреть сообщение
worker = std::thread(work); // ТАКИМ образом создается новый поток или ПЕРЕиспользуется уже старый ?
* * worker.join();
Создаётся новый. Старому делается terminate https://en.cppreference.com/w/... perator%3D
1
-41 / 49 / 5
Регистрация: 10.01.2017
Сообщений: 1,915
18.08.2019, 12:12  [ТС]
Подскажите пожалуйста, а после вызова terminate, поток или информация о потоке удаляется из памяти или какое тотместо в памяти об этом потоке сохраняется ?
То есть не модет получится так, что ну к прмеру, вот некоторые простые сервера на каждый входящий запрос создают новый отдельный поток, не получится ли так, что хоть потоки и сделались join() и/или trrminate, но какая то информация о них в памяти все равно занимается и рано или поздно они просто займут всю память ?
0
285 / 176 / 21
Регистрация: 16.02.2018
Сообщений: 666
18.08.2019, 13:12
Цитата Сообщение от oleg-m1973 Посмотреть сообщение
Старому делается terminate
0
 Аватар для eva2326
1673 / 501 / 107
Регистрация: 17.05.2015
Сообщений: 1,518
18.08.2019, 13:59
Цитата Сообщение от oleg-m1973 Посмотреть сообщение
Создаётся новый. Старому делается terminate
0
-41 / 49 / 5
Регистрация: 10.01.2017
Сообщений: 1,915
18.08.2019, 14:20  [ТС]
terminate может сделатся в отношении потока который еще не завершился, то есть который еще не дошел до join или detach ?
0
Эксперт С++
 Аватар для hoggy
8973 / 4319 / 960
Регистрация: 15.11.2014
Сообщений: 9,760
18.08.2019, 14:25
Цитата Сообщение от Optimus11 Посмотреть сообщение
terminate может сделатся в отношении потока который еще не завершился, то есть который еще не дошел до join или detach ?

да.

очевидно жеж: нельзя уничтожить поток, которого уже не существует.

Цитата Сообщение от Optimus11 Посмотреть сообщение
worker.join(); *// <--- завершился
worker = std::thread(work); // ТАКИМ образом создается новый поток или ПЕРЕиспользуется уже старый ?
а вот тебе, похоже не очевидно?
как можно переиспользовать то, чего уже не существует?

и потом, ты внимательно прочел фразу ?
Цитата Сообщение от hoggy Посмотреть сообщение
worker = std::thread(work); // <--- запуск нового потока
тут написано, "запуск нового потока" или "ПЕРЕиспользуется уже старый" ?

выводы сделай сам.
1
-41 / 49 / 5
Регистрация: 10.01.2017
Сообщений: 1,915
18.08.2019, 14:35  [ТС]
Понял, спасибо! Был не внимателен.
А в итоге после:
C++
1
worker.join();
Информация о ранее созданном потоке worker более нет в пямяти, вообще ни какой ?
0
-41 / 49 / 5
Регистрация: 10.01.2017
Сообщений: 1,915
19.08.2019, 13:48  [ТС]
Подскажите пожалуйста, а чем принципиально отличается thread от async/future ?

Ну вот предположим есть два Входящих запроса от клинта, найти какое то число и ссответсвующую этому числу информацию и выдать клиенту.
Есть соответсвенно массив с инфориацией.

Один поток:Ну вот предположим пришел запрос от первого клиента, запустили поиск, и через милисиккнжу пришел запрос от второго клиента. Причем запрос первого клиента по случайно будет вполнятся аж целую минуту, ну долго искать для него информацию, а значит второй клиент будет вме это время ждать. Гехорошо.

Два потока: создаеи на кажый Входящий запрос поток и там ищем.
В случае, если два запроса в одном потоке обробатывались бы по минуте, то первый абонент получил бы раньше. Второй прямолинейно позже, если в двух потоках, то кажый получит в одно и тоже время, хотя первый бы мог получить раньше.
Соответмвенно после выполнение функции потоки joinятся и получаем результат выполнения.

Асинхронный: приходят два Входящих тех же запроса, для каждого запроса создаем асинхронную операцию, там внутри std async тоже за человека создает отдельные потоки, и после получения нужного результат при вызове future.get() (я так понимаю это некий аналог join ?) В нужном месте получаем результат.

Если вме примерно в самом общем смысле так ? То в чем принциаиалбное отличие ?
0
6772 / 4565 / 1844
Регистрация: 07.05.2019
Сообщений: 13,726
19.08.2019, 13:56
Цитата Сообщение от Optimus11 Посмотреть сообщение
Подскажите пожалуйста, а чем принципиально отличается thread от async/future ?
std::thread - это создание нового потока, довольно дорогая операция, поэтому лучше это делать пореже.
std::async - выполняет задачу на пуле потоков. Т.е., как правило, берёт уже созданный поток и говорит ему, чтоб исполнил код.

Добавлено через 59 секунд
Для выполнения запросов от клиентов лучше использовать std::async
0
-41 / 49 / 5
Регистрация: 10.01.2017
Сообщений: 1,915
19.08.2019, 14:01  [ТС]
А откуда возьмется пул потоков ? Он создается при первом вызове future<> func = async(std::launch::async, Foonc) ?

Если так и если разница только в принципе созбания потока, то почему бы вмегда не использовать async ?
0
6772 / 4565 / 1844
Регистрация: 07.05.2019
Сообщений: 13,726
19.08.2019, 14:08
Цитата Сообщение от Optimus11 Посмотреть сообщение
А откуда возьмется пул потоков ? Он создается при первом вызове future<> func = async(std::launch::async, Foonc) ?
При запуске процесса создаётся пул потоков.

Цитата Сообщение от Optimus11 Посмотреть сообщение
сли так и если разница только в принципе созбания потока, то почему бы вмегда не использовать async ?
Потому что пул потоков используют все, поэтому лучше запускать там отдельные задачи, не слишком длинные - запустилась/завершилась. Соответственно, при таком механизме есть дополнительные накладные расходы.
Поток же, как правило, создаётся менее универсальным, для решения какой-то конкретной задачи. Т.е. у тебя не будет этих расходов и ты можешь быть уверен, что никто чужой этот поток не залочит
0
-41 / 49 / 5
Регистрация: 10.01.2017
Сообщений: 1,915
19.08.2019, 14:11  [ТС]
А можно самому создать пул thread потоков за раз и потом их использовать, как хочешь ?
И async не надо тогда использовать будет.
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
BasicMan
Эксперт
29316 / 5623 / 2384
Регистрация: 17.02.2009
Сообщений: 30,364
Блог
19.08.2019, 14:11
Помогаю со студенческими работами здесь

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

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

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

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

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


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

Или воспользуйтесь поиском по форуму:
20
Ответ Создать тему
Новые блоги и статьи
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