C++. Сборник рецептов.
12.5. Передача аргумента функции потока.
Проблема.
Требуется передать аргумент в вашу функцию потока, однако средствами библиотеки Boost Threads предусматривается передача только функторов без аргументов.
Решение.
Создайте адаптер функтора, который принимает ваши параметры и возвращает функтор без параметров. Адаптер функтора можно использовать там, где должен был бы быть функтор потока. Пример 12.6 показывает, как это можно сделать.
Пример 12.6. Передача аргументов функции потока.
#include <iostream>
#include <string>
#include <functional>
#include <boost/thread/thread.hpp>
// typedef используется для того, чтобы приводимые ниже объявления лучше.
// читались.
Typedef void (*WorkerFunPtr)(const std::string&);
Template<typename FunT, // Тип вызываемой функции.
typename ParamT> // тип ее параметра.
Struct Adapter {
Adapter(FunT f, ParamT& p) : // Сконструировать данный адаптер и.
f_(f), p_(&p) {} // установить члены на значение функции и ее.
// аргумента.
void operator()() { // Просто вызов функции с ее аргументом.
f_(*p_);
}
Private:
FunT f_;
ParamT* p_; // Использовать адрес параметра. чтобы избежать лишнего.
// копирования.
};
Void worker(const std::string& s) {
std::cout << s << '\n';
}
Int main() {
std::string s1 = "This is the first thread!";
std::string s2 = "This is the second thread!";
boost::thread thr1(Adapter<WorkerFunPtr, std::string>(worker, s1));
boost::thread thr2(Adapter<WorkerFunPtr, std::string>(worker, s2));
thr1.join();
thr2.join();
}
Обсуждение.
Здесь приходится решать принципиальную проблему, причем характерную не только для потоков или проекта Boost, а общую проблему, возникающую при необходимости передачи функтора с одной сигнатурой туда, где требуется другая сигнатура. Решение состоит в создании адаптера.
Синтаксис может показаться немного путаным, но фактически в примере 12.6 создается временный функтор, который может вызываться конструктором потока как функция без аргументов (требуется именно такая функция). Но прежде всего используйте typedef, чтобы указатель функции лучше воспринимался в тексте.
Typedef void (*WorkerFunPtr)(const std::string&);
Это создает тип WorkerFunPtr, который является указателем на функцию, принимающую по ссылке аргумент типа string и возвращающую тип void. После этого я создал шаблон класса Adapter. Он обеспечивает инстанцирование динамического функтора. Обратите внимание на конструктор:
Template<Typename FunT,
typename ParamT>
Struct Adapter {
Adapter(FunT f, ParamT& p) : f_(f), p_(&p) {}.
// ...
Конструктор только инициализирует два члена, которые могут быть любого типа, но нам нужно, чтобы это был указатель на функцию и некоторый параметр p любого типа. Ради повышения эффективности я сохраняю адрес параметра, а не его значение.
Теперь рассмотрим следующую строку главного потока.
Boost::thread thr1(Adapter<WorkerFunPtr, std::string>(worker, s1)).
Аргумент конструктора thr1 представляет собой реализацию шаблона класса Adapter, использующую в качестве параметров два типа WorkerFunPtr и std::string. Это именно те два типа, которые являются членами адаптера f_ и p_. Наконец, Adapter перегружает operator(), поэтому он может вызываться как функция. Его вызов означает просто выполнение следующей функции.
F_(*p_);
Применяя шаблон класса Adapter, можно передавать аргументы функциям потока, причем делается это за счет лишь небольшого усложнения синтаксиса. Если требуется передавать еще один аргумент, просто добавьте дополнительный тип и переменную-член в шаблон Adapter. Этот подход привлекателен тем, что позволяет создавать набор шаблонов классов обобщенного адаптера и использовать их в различных контекстах.
- 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.
- 55.
- 56.
- 57.
- 58.
- 59.
- 60.
- 61.
- 62.
- 63.
- 64.
- 65.
- 66.
- 67.
- 68.
- 69.
- 70.
- 71.
- 72.
- 73.
- 74.
- 75.
- 76.
- 77.
- 78.
- 79.
- 80.
- 81.
- 82.
- 83.
- 84.
- 85.
- 86.
- 87.
- 88.
- 89.
- 90.
- 91.
- 92.
- 93.
- 94.
- 95.
- 96.
- 97.
- 98.
- 99.
- 100.
- 101.
- 102.
- 103.
- 104.
- 105.
- 106.
- 107.
- 108.
- 109.
- 110.
- 111.
- 112.
- 113.
- 114.
- 115.
- 116.
- 117.
- 118.
- 119.
- 120.
- 121.
- 122.
- 123.
- 124.
- 125.
- 126.
- 127.
- 128.
- 129.
- 130.
- 131.
- 132.
- 133.
- 134.
- 135.
- 136.
- 137.
- 138.
- 139.
- 140.
- 141.
- 142.
- 143.
- 144.
- 145.
- 146.
- 147.
- 148.
- 149.
- 150.
- 151.
- 152.
- 153.
- 154.
- 155.
- 156.
- 157.
- 158.
- 159.
- 160.
- 161.
- 162.
- 163.
- 164.
- 165.
- 166.
- 167.
- 168.
- 169.
- 170.
- 171.
- 172.
- 173.
- 174.
- 175.
- 176.
- 177.
- 178.
- 179.
- 180.
- 181.
- 182.
- 183.
- 184.
- 185.
- 186.
- 187.
- 188.
- 189.
- 190.
- 191.
- 192.
- 193.
- 194.
- 195.
- 196.
- 197.
- 198.
- 199.
- 200.
- 201.
- 202.
- 203.
- 204.