Форум программистов, компьютерный форум, киберфорум
С++ для начинающих
Войти
Регистрация
Восстановить пароль
 
 
Рейтинг 5.00/27: Рейтинг темы: голосов - 27, средняя оценка - 5.00
32 / 29 / 3
Регистрация: 10.01.2017
Сообщений: 1,227
1

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

15.08.2019, 21:11. Показов 5255. Ответов 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

Помощь в написании контрольных, курсовых и дипломных работ здесь.

Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
15.08.2019, 21:11
Ответы с готовыми решениями:

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

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

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

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

35
2723 / 1887 / 559
Регистрация: 05.06.2014
Сообщений: 5,499
15.08.2019, 21:43 2
Ну так сложите все треды в массив какого вам надо размера.
1
Don't worry, be happy
17168 / 10052 / 1934
Регистрация: 27.09.2012
Сообщений: 25,042
Записей в блоге: 1
15.08.2019, 22:03 3
Цитата Сообщение от Optimus11 Посмотреть сообщение
Но, реально не могу понять, возможно ли это и как.
можете посмотреть идею здесь: Многопоточный проход по матрице
2
6738 / 4537 / 1839
Регистрация: 07.05.2019
Сообщений: 13,725
Записей в блоге: 1
16.08.2019, 09:13 4
Лучший ответ Сообщение было отмечено 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
32 / 29 / 3
Регистрация: 10.01.2017
Сообщений: 1,227
16.08.2019, 13:27  [ТС] 5
Спасибо! Работает.

Позвольте пожалуйста несколько общих вопросов:
1)А что происходит с потоком, когда весь код внутри потока выполнен или когда поток достиг join ? Он как то удаляется ?
2)возможно ли сделать, чтобы к примеру, вот есть три потока к примеру, вме они заняты поиском числа в одном и том же массиве и вот предположи во 2ом потоке нужное значение найдено и он завершил свою работу, но 1ый и 3ий еще продолжают искать и тратить время процессора, можно ли как то принудительно остановить работу нужных потоков ?
0
6738 / 4537 / 1839
Регистрация: 07.05.2019
Сообщений: 13,725
Записей в блоге: 1
16.08.2019, 13:35 6
Цитата Сообщение от 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
Эксперт С++
8426 / 4099 / 894
Регистрация: 15.11.2014
Сообщений: 9,209
16.08.2019, 14:01 7
Лучший ответ Сообщение было отмечено 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:
Код
main: запуск!
thread: делаю вид, что работаю...
thread: делаю вид, что работаю...
thread: делаю вид, что работаю...
thread: делаю вид, что работаю...
main: сигнал об остановке
main: ожидаю завершения работы треда
thread: рабочий день закончился. я пошёль домой
main: thread завершился. конец программы
1
32 / 29 / 3
Регистрация: 10.01.2017
Сообщений: 1,227
16.08.2019, 15:55  [ТС] 8
Спасибо!!

Подсажите:
C++
1
2
3
4
5
std::thread worker(work);
    worker.join();  // <--- завершился
    
worker = std::thread(work); // ТАКИМ образом создается новый поток или ПЕРЕиспользуется уже старый ?
    worker.join();
0
6738 / 4537 / 1839
Регистрация: 07.05.2019
Сообщений: 13,725
Записей в блоге: 1
16.08.2019, 16:04 9
Цитата Сообщение от Optimus11 Посмотреть сообщение
worker = std::thread(work); // ТАКИМ образом создается новый поток или ПЕРЕиспользуется уже старый ?
* * worker.join();
Создаётся новый. Старому делается terminate https://en.cppreference.com/w/... perator%3D
1
32 / 29 / 3
Регистрация: 10.01.2017
Сообщений: 1,227
18.08.2019, 12:12  [ТС] 10
Подскажите пожалуйста, а после вызова terminate, поток или информация о потоке удаляется из памяти или какое тотместо в памяти об этом потоке сохраняется ?
То есть не модет получится так, что ну к прмеру, вот некоторые простые сервера на каждый входящий запрос создают новый отдельный поток, не получится ли так, что хоть потоки и сделались join() и/или trrminate, но какая то информация о них в памяти все равно занимается и рано или поздно они просто займут всю память ?
0
285 / 176 / 21
Регистрация: 16.02.2018
Сообщений: 666
18.08.2019, 13:12 11
Цитата Сообщение от oleg-m1973 Посмотреть сообщение
Старому делается terminate
0
884 / 340 / 78
Регистрация: 17.05.2015
Сообщений: 1,095
18.08.2019, 13:59 12
Цитата Сообщение от oleg-m1973 Посмотреть сообщение
Создаётся новый. Старому делается terminate
Как создать многопоточность
0
32 / 29 / 3
Регистрация: 10.01.2017
Сообщений: 1,227
18.08.2019, 14:20  [ТС] 13
terminate может сделатся в отношении потока который еще не завершился, то есть который еще не дошел до join или detach ?
0
Эксперт С++
8426 / 4099 / 894
Регистрация: 15.11.2014
Сообщений: 9,209
18.08.2019, 14:25 14
Цитата Сообщение от Optimus11 Посмотреть сообщение
terminate может сделатся в отношении потока который еще не завершился, то есть который еще не дошел до join или detach ?

да.

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

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

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

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

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

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

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

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

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

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

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

Цитата Сообщение от Optimus11 Посмотреть сообщение
сли так и если разница только в принципе созбания потока, то почему бы вмегда не использовать async ?
Потому что пул потоков используют все, поэтому лучше запускать там отдельные задачи, не слишком длинные - запустилась/завершилась. Соответственно, при таком механизме есть дополнительные накладные расходы.
Поток же, как правило, создаётся менее универсальным, для решения какой-то конкретной задачи. Т.е. у тебя не будет этих расходов и ты можешь быть уверен, что никто чужой этот поток не залочит
0
32 / 29 / 3
Регистрация: 10.01.2017
Сообщений: 1,227
19.08.2019, 14:11  [ТС] 20
А можно самому создать пул thread потоков за раз и потом их использовать, как хочешь ?
И async не надо тогда использовать будет.
0
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
19.08.2019, 14:11

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

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

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

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


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

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

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2021, vBulletin Solutions, Inc.