我正在尝试将一堆 lambda 表达式推送到 C++ 的线程池上。 我正在使用 boost::basic_thread_pool 来顺序处理一个人的工作(lambda 函子)并安排在工作队列中。
当我将工作放入worker_thread_pool时,放入了lambda函数,并且lambda函数没有名称,因此即使我想记录也无法记录lambda函数。当我放置 lambda 函数时,我询问是否有办法启用日志记录。
thread_pool tp{4};
tp.submit([]() {sleep(4);}); // i wants to log some issue If it takes more than a second. but no information about lambda expression
谁能告诉我这是否可行?
谢谢
asio::thread_pool
没有提交会员功能。
此外,命名任务不是池的责任。如果需要,可以用名称发布任务。
也许您正在使用一个日志框架,可以从编译器定义的宏中检测函数名称,例如 Boost Log:
void Hibernation() {
BOOST_LOG_FUNCTION();
LOG() << "Start";
sleep(4);
LOG() << "Exit";
}
这不适用于 lambda,因为 lambda1 的一个简洁定义是作为一个未命名的函数。但是您可以添加一个包装器来添加范围名称,再次使用 Boost Log 作为示例:
template <size_t N, typename F> auto named(char const (&n)[N], F&& f) {
return [&n, f = std::forward<F>(f)](auto&&... args) mutable -> decltype(auto) {
BOOST_LOG_NAMED_SCOPE(n);
std::move(f)(std::forward<decltype(args)>(args)...);
};
}
注意如何将
与显式名称一起使用,而不是BOOST_LOG_NAMED_SCOPE
。请参阅文档:用户可以用 BOOST_LOG_NAMED_SCOPE 宏替换有问题的 BOOST_LOG_FUNCTION 用法,并显式写入所需的范围名称BOOST_LOG_FUNCTION
#include <boost/asio.hpp>
#include <boost/log/attributes/named_scope.hpp>
#include <boost/log/expressions.hpp>
#include <boost/log/trivial.hpp>
#include <boost/log/utility/setup/console.hpp>
auto& s_log = []() -> auto& {
using namespace boost::log;
add_console_log(std::cout,
keywords::format = expressions::stream
<< "[" << expressions::format_named_scope("Scope", keywords::format = "%F:%l:%c")
<< "] " << expressions::message);
auto core = core::get();
core->add_global_attribute("Scope", attributes::named_scope());
static trivial::logger_type instance;
return instance;
}();
#define LOG() BOOST_LOG(s_log)
template <size_t N, typename F> auto named(char const (&n)[N], F&& f) {
return [&n, f = std::forward<F>(f)](auto&&... args) mutable -> decltype(auto) {
BOOST_LOG_NAMED_SCOPE(n);
std::move(f)(std::forward<decltype(args)>(args)...);
};
}
void Hibernation() {
BOOST_LOG_FUNCTION();
LOG() << "Start";
sleep(4);
LOG() << "Exit";
}
int main() {
BOOST_LOG_FUNCTION();
LOG() << "Hello world";
boost::asio::thread_pool tp{4};
post(tp, Hibernation);
auto task = []() {
LOG() << "Start";
sleep(1);
LOG() << "Exit";
};
sleep(1);
post(tp, task); // naked lamda, no thread scope at all
sleep(1);
post(tp, named("SleepingBeauty", task)); // named
tp.join();
LOG() << "Bye";
}
显示:
[test.cpp:35:main] Hello world
[test.cpp:28:Hibernation] Start
[] Start
[test.cpp:22:SleepingBeauty] Start
[] Exit
[test.cpp:22:SleepingBeauty] Exit
[test.cpp:28:Hibernation] Exit
[test.cpp:35:main] Bye
我建议不要(ab)使用
asio::thread_pool
来进行您自己的面向任务的工作排队,从而消除对其缺乏功能的抱怨。不过,为了幽默一下这个想法,您也可以通过以下方式向池的线程添加正确的线程名称:
#include <boost/asio.hpp>
#include <boost/log/attributes/named_scope.hpp>
#include <boost/log/expressions.hpp>
#include <boost/log/trivial.hpp>
#include <boost/log/utility/setup/console.hpp>
#include <deque>
auto& s_log = []() -> auto& {
using namespace boost::log;
add_console_log(std::cout,
keywords::format = expressions::stream
<< "[" << expressions::format_named_scope("Scope", keywords::format = "%c")
<< "] " << expressions::message);
auto core = core::get();
core->add_global_attribute("Scope", attributes::named_scope());
static trivial::logger_type instance;
return instance;
}();
#define LOG() BOOST_LOG(s_log)
template <size_t N, typename F> auto named(char const (&n)[N], F&& f) {
return [&n, f = std::forward<F>(f)](auto&&... args) mutable -> decltype(auto) {
BOOST_LOG_NAMED_SCOPE(n);
std::move(f)(std::forward<decltype(args)>(args)...);
};
}
void Hibernation() {
BOOST_LOG_FUNCTION();
LOG() << "Start";
sleep(4);
LOG() << "Exit";
}
static void Worker(char const (&name)[3], boost::asio::thread_pool& pool) {
BOOST_LOG_FUNCTION();
BOOST_LOG_NAMED_SCOPE(name);
pool.attach();
}
int main() {
BOOST_LOG_FUNCTION();
LOG() << "Hello world";
boost::asio::thread_pool tp{0};
std::deque<std::thread> workers;
workers.emplace_back(Worker, std::ref("#1"), ref(tp));
workers.emplace_back(Worker, std::ref("#2"), ref(tp));
workers.emplace_back(Worker, std::ref("#3"), ref(tp));
workers.emplace_back(Worker, std::ref("#4"), ref(tp));
post(tp, Hibernation);
auto task = [] { LOG() << "Start"; sleep(1); LOG() << "Exit"; };
sleep(1);
post(tp, task); // naked lamda, no thread scope at all
sleep(1);
post(tp, named("SleepingBeauty", task)); // named
tp.join();
for (auto& w: workers)
if (w.joinable())
w.join();
LOG() << "Bye";
}
带输出
[main] Hello world
[Worker->#3->Hibernation] Start
[Worker->#2] Start
[Worker->#4->SleepingBeauty] Start
[Worker->#2] Exit
[Worker->#4->SleepingBeauty] Exit
[Worker->#3->Hibernation] Exit
[main] Bye
请注意,看看这变得多么笨拙,在我看来,我们肯定已经跨过了“滥用
”的门槛。asio::thread_pool
¹ 掩盖闭包语义(捕获)