Здорова ребятки, сегодня разберем такую штуку как boost::thread. Эта библиотека предназначена для создания потоков. Как подключить и настроить boost вы можите почитать по ссылке Подключени и работа boost в visual studio 2010. Разберем несколько примеров как создаются потоки.
Содержание:
1. Вызов функции выполняющейся в потоке
2. Вызов функции с параметрами выполняющейся в потоке
3. Использование функтора
4. Объектный в котором передается функция в поток
5. Объектный способ, который управляет своими потоками
1. Вызов функции выполняющейся в потоке
У нас есть простой код в котором создано де функции и создано два потока, каждая функция передается своему потоку по ссылке и выполняется. В коде ниже используется функция join для каждого потока для того чтобы дождаться завершения его выполнения, так же можно одну и туже функцию передавать разным потокам.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
#include <boost/thread/thread.hpp> #include <iostream> using std::cout; using std::endl; void f1() { cout <<"Hello world, I'm a thread1!"<<endl; } void f2() { cout <<"Hello world, I'm a thread2!"<<endl; } int main() { boost::thread t1(&f1);//вызываем функцию f1 boost::thread t2(&f2);//добавляем функцию f2 в поток t1.join();//ждем завершение потока t1 t2.join();//ждем завершение потока t2 //Оба потока завершены используем их результаты return 0; } |
Выводится на экран:
2. Вызов функции с параметрами выполняющейся в потоке
Теперь рассмотрим пример кода в котором мы вызовем уже функцию с параметрами в потоках. Функцию можно передавать и просто по значению как в коде ниже
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
#include <boost/thread/thread.hpp> #include <iostream> using std::cout; using std::endl; void f1(double n,int k) { cout <<"Hello world, I'm a thread n= "<<n<<" k= "<<k<<endl; } int main() { boost::thread t1(f1,1,10);//вызываем функцию f1 boost::thread t2(f1,2,20);//добавляем функцию f1 в поток boost::thread t3(&f1,3,30);//добавляем функцию f1 в поток boost::thread t4(&f1,4,40);//добавляем функцию f1 в поток t1.join(); t2.join(); t3.join(); t4.join(); //ждем пока все потоки будут завершены return 0; } |
Вывод на экран:
3. Использование функтора
Функтор — это класс в котором перегружен operator(), который благодаря этому может вести себя и как объект и как функция одновременно. Метод определенный при перегрузке () срабатывает при вызове объекта как функции.
Ниже пример кода с функтором который вычисляет куб в несколько потоков
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 |
#include <boost/thread/thread.hpp> #include <iostream> using std::cout; using std::endl; //создаем функтор для подсчета куба class kyb { double n; public: kyb(double a):n(a){}//конструктор void operator()()//вычисление будет производится при вычислении { double k=n*n*n; cout <<"n= "<<n<<" kyb= "<<k<<endl; } }; int main() { //создаем объекты kyb k1(1); kyb k2(2); kyb k3(3); kyb k4(3); //создаем потоки boost::thread t1(k1);//вызываем функцию f1 boost::thread t2(k2);//добавляем функцию f1 в поток boost::thread t3(k3);//добавляем функцию f1 в поток boost::thread t4(k4);//добавляем функцию f1 в поток t1.join(); t2.join(); t3.join(); t4.join(); //ждем пока все потоки будут завершены //вызов просто объектов как функций без потоков cout <<"_____________"<<endl; k1(); k2(); k3(); k4(); return 0; } |
Вывод на экран:
[tip]Важно понимать, что конструктор boost::thread берет функтор-параметр по значению, что означает создание копии объекта.
Не стоит забывать об этом при реализации функтора, чтобы избежать возможных проблем.[/tip]
4. Объектный в котором передается функция в поток
В данном способе в конструктор boost::tread необходимо передать имя функции используя имя класса, ссылку на экземпляр класса и при необходимости параметр. В примере ниже мы вычисляем куб и с помощью третьего параметра умножаем его на 2 и выводим на экран
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 |
#include <boost/thread/thread.hpp> #include <iostream> using std::cout; using std::endl; //создаем функтор для подсчета куба class kyb { double n; public: kyb(double a):n(a){}//конструктор void raschet_cub(double a)//вычисление будет производится при вычислении { double k=n*n*n*a; cout <<"n= "<<n<<" a= "<<a<<" kyb= "<<k<<endl; } }; int main() { //создаем объекты kyb k1(1); kyb k2(2); kyb k3(3); kyb k4(3); //создаем потоки и вызываем функцию из объекта kyb::raschet_cub boost::thread t1(&kyb::raschet_cub,&k1,2); boost::thread t2(&kyb::raschet_cub,&k2,2); boost::thread t3(&kyb::raschet_cub,&k3,2); boost::thread t4(&kyb::raschet_cub,&k4,2); t1.join(); t2.join(); t3.join(); t4.join(); //ждем пока все потоки будут завершены return 0; } |
Вывод на экран:
[tip]Имейте в виду что если вы создадите объект, запустите его метод в потоке, а потом объект выйдет из области видимости и уничтожится до того, как поток завершился, проблем не оберетесь.[/tip]
5. Объектный способ, который управляет своими потоками
Вы можете создать множество объектов, которые будут управлять своими потоками. Наверняка, это самый удобный способ, если требуется создать многопоточную программу.
В коде ниже поток создается внутри объекта, а сам объект предоставляет методы для управления потоком. Смотрим код.
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 |
#include <boost/thread/thread.hpp> #include <iostream> using std::cout; using std::endl; //создаем функтор для подсчета куба class kyb { boost::thread Thread;//хранит поток public: kyb(){}//конструктор //создание потока void start(double n)//создаем поток { Thread=boost::thread(&kyb::raschet_cub,this,n);//создается поток } //закрытие потока void join() { Thread.join(); } //функция рассчитывает куб числа void raschet_cub(double n)//вычисление будет производится при вычислении { double k=n*n*n; cout <<"n= "<<n<<" kyb= "<<k<<endl; } }; int main() { //создаем объекты kyb k1; kyb k2; kyb k3; kyb k4; //создаем потоки и вызываем функцию из объекта kyb::raschet_cub k1.start(1); k2.start(2); k3.start(3); k4.start(4); k1.join(); k2.join(); k3.join(); k4.join(); //ждем пока все потоки будут завершены return 0; } |
Вывод на экран:
На этом пожалуй все, в принципе понятно как использовать потоки, тут ничего сложного нету 🙂
[youtube]https://www.youtube.com/watch?v=OAhHX2LheMI[/youtube]