Прежде всего, я хочу извиниться за объемный пост. Я хотел быть максимально подробным.
Я застрял в этой проблеме уже несколько дней, и на удивление мало информации о правильном использовании boost::packaged_task
в функции, которая имеет входные параметры.
Системная информация
- C++03
- Повышение 1.54.0
- CMake 2.8.9
Первоначальное требование
- У меня есть установка, состоящая из клиента (ов), сервера и устройства (а).
- A client interacts with a device by sending requests to the server.
- These requests are examined and routed to the appropriate device.
- Запросы обрабатываются асинхронно и иногда по разным причинам помещаются в очередь через
boost::asio::io_service::strand
.
- Requests are placed into a queue, local to the device itself.
- When the request has been acknowledged (not necessarily completed), it is assigned an ID, and returned to the client.
Пакетная задача
После просмотра boost :: Futures мы решили, что boost :: packaged_task сделает именно то, что нам нужно. Однако, похоже, есть ошибка в реализации пакетной задачи.
Похоже, что у packaged_task есть несколько разных шаблонов на выбор:
packaged_task<R>
packaged_task<R()>
packaged_task<R(ArgTypes)>
- Другие, которые мне могут не хватать.
Чтобы убедиться, что я правильно использую функцию, я начал с простого; используя простой пример на странице boost :: futures в качестве отправной точки. Оттуда я создал четыре простых функции:
- int return, без параметров.
- int return с параметрами.
std::string
возврат, без параметров.std::string
возврат с параметрами.
Тестовые функции
std::string ans("forty two");
int int_no_params()
{
return 42;
}
int int_with_params(int param)
{
return param;
}
std::string string_no_params()
{
return std::string("forty two");
}
std::string string_with_params(std::string & param) // Have tried both with and without '&'
{
return param;
}
ПРИМЕР 1:
int function(void)
//! Compiles and produces correct result.
{
boost::packaged_task<int()> example(int_no_params);
boost::future<int> f = example.get_future();
boost::thread task(boost::move(example));
int answer = f.get();
std::cout << "Answer to life and whatnot, in English: " << answer << std::endl;
task.join();
}
ПРИМЕР 2:
std::string function(void)
//! Compiles and produces correct result.
{
boost::packaged_task<std::string()> example(string_no_params);
boost::future<std::string> f = example.get_future();
boost::thread task(boost::move(example));
std::string answer = f.get();
std::cout << "string_no_params: " << answer << std::endl;
task.join();
}
ПРИМЕР 3:
std::string(std::string& param)
Нет резьбы
//! Doesn't compile.
//! error: variable ‘boost::packaged_task<std::basic_string<char>(std::basic_string<char>&)> example’ has initializer but incomplete type
{
boost::packaged_task<std::string(std::string&)> example(string_with_params);
boost::future<std::string> f = example.get_future();
example(ans);
std::string answer = f.get();
std::cout << "string_with_params: " << answer << std::endl;
}
ПРИМЕР 4:
с использованием boost :: threading
//! Doesn't compile.
//! error: variable ‘boost::packaged_task<std::basic_string<char>(std::basic_string<char>&)> example’ has initializer but incomplete type
{
boost::packaged_task<std::string(std::string&)> example(string_with_params);
boost::future<std::string> f = example.get_future();
boost::thread task(boost::move(example), ans);
std::string answer = f.get();
std::cout << "string_with_params: " << answer << std::endl;
task.join();
}
ПРИМЕР 5:
Использование расширенных инициализаторов в объявлении packaged_task
//! Doesn't compile in C++03, C++11 only.
//! error: extended initializer lists only available with -std=c++11 or -std=gnu++11 [-Werror]
{
boost::packaged_task<std::string(std::string&)> example
{ boost::bind(&string_with_params, ans) };
boost::future<std::string> f = example.get_future();
boost::thread task(boost::move(example), ans);
std::string answer = f.get();
std::cout << "string_with_params: " << answer << std::endl;
task.join();
}
ПРИМЕР 6:
Потоковый, с использованием shared_ptr
Следующее использование typedef boost::packaged_task<std::string(std::string&)> task_t;
Поскольку упакованные задачи не могут быть скопированы, привязка shared_ptr<T>::operator()
к task
была предложенным решением, найденным здесь.
// error: invalid use of incomplete type ‘class boost::packaged_task<std::basic_string<char>(std::basic_string<char>&)>’
// error: incomplete type ‘task_t {aka boost::packaged_task<std::basic_string<char>(std::basic_string<char>&)>}’ used in nested name specifier
// boost/thread/future.hpp:1320:11: error: declaration of ‘class boost::packaged_task<std::basic_string<char>(std::basic_string<char>&)>’
{
boost::shared_ptr<task_t> example = boost::make_shared<task_t>(boost::bind(&string_with_params, ans));
boost::future<std::string> f = example->get_future();
boost::thread task(boost::bind(&task_t::operator(), example));
std::string answer = f.get();
std::cout << "string_with_params: " << answer << std::endl;
task.join();
}
ПРИМЕР 7:
Использование boost::asio::io_service
и boost::bind
// ошибка: недопустимое использование неполного типа 'class boost :: packaged_task (std :: basic_string &)>' // ошибка: неполный тип 'task_t {aka boost :: packaged_task (std :: basic_string &)>}' используется во вложенном имени спецификатор // boost / thread / future.hpp: 1320: 11: error: объявление класса boost :: packaged_task (std :: basic_string &)> '
{
boost::asio::io_service io_service;
boost::thread_group threads;
boost::asio::io_service::work work(io_service);
for (int i = 0; i < 3; ++i)
{
threads.create_thread(boost::bind(&boost::asio::io_service::run,
&io_service));
}
boost::shared_ptr<task_t> example = boost::make_shared<task_t>(boost::bind(&string_with_params, ans));
boost::future<std::string> f = example->get_future();
io_service.post(boost::bind(&task_t::operator(), example));
std::string answer = f.get();
std::cout << "string_with_params: " << answer << std::endl;
threads.join_all();
}
Что-то я здесь делаю ужасно неправильно? Мне кажется, что я исчерпывающе протестировал это и не продвинулся вперед. Я пробовал любую другую комбинацию привязок, потоков и задач, чтобы заставить это работать, но этого просто не происходит. Я ценю любую помощь, которую вы оказываете.
В заключение:
У меня есть рабочее решение, использующее фьючерсы и обещания, и, используя частную функцию для публикации в моем потоке, я возвращаю действительное будущее. Эта проблема не обязательно связана с ошибкой пользователя.
Спасибо за чтение.