如何自动命名工作线程池内的 lambda 仿函数

问题描述 投票:0回答:1

我正在尝试将一堆 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

谁能告诉我这是否可行?

谢谢

c++ multithreading boost boost-asio
1个回答
0
投票

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_FUNCTION
。请参阅文档:用户可以用 BOOST_LOG_NAMED_SCOPE 宏替换有问题的 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
”的门槛。


¹ 掩盖闭包语义(捕获)

© www.soinside.com 2019 - 2024. All rights reserved.