asio :: strand上的任务在单个线程上运行

时间:2018-12-20 23:18:01

标签: c++ asio stdasync

我使用4a here

中库的独立版本修改了一个asio链示例
#include <iostream>
#include <asio.hpp>
#include <future>
#include <thread>
#include <mutex>
#include <chrono>
using namespace std::chrono_literals;

namespace util
{
static std::mutex s_mtx_print;

// Default argument value
// https://en.cppreference.com/w/cpp/language/default_arguments
template <typename... Args>
void sync_print(const bool log_thread_id, Args &&... args)
{
    std::lock_guard<std::mutex> print_lock(s_mtx_print);
    if (log_thread_id)
    {
        std::cout << "[" << std::this_thread::get_id() << "] ";
    }
    (std::cout << ... << args) << '\n';
}

}

void Worker(std::unique_ptr<asio::io_service> &ios)
{
    util::sync_print(true, " Started...");
    if(ios) {ios->run();}
    util::sync_print(true, " End");
}

void PrintNum(int n)
{
    std::cout << "[" << std::this_thread::get_id() << "] " << n << '\n';
    std::this_thread::sleep_for(300ms);
}

void OrderedInvocation(std::unique_ptr<asio::io_service::strand> &up_strand)
{
    if(up_strand)
    {
        up_strand->post(std::bind(&PrintNum, 1));
        up_strand->post(std::bind(&PrintNum, 2));
        up_strand->post(std::bind(&PrintNum, 3));
        up_strand->post(std::bind(&PrintNum, 4));
        up_strand->post(std::bind(&PrintNum, 5));
        up_strand->post(std::bind(&PrintNum, 6));
        up_strand->post(std::bind(&PrintNum, 7));
        up_strand->post(std::bind(&PrintNum, 8));
        up_strand->post(std::bind(&PrintNum, 9));
    }
    else{
        std::cerr << "Invalid strand" << '\n';
    }
}

int main()
{
    util::sync_print(true, "section 4 started ...");
    auto up_ios = std::make_unique<asio::io_service>();
    auto up_work = std::make_unique<asio::io_service::work>(*up_ios);
    auto up_strand = std::make_unique<asio::io_service::strand>(*up_ios);

    std::vector<std::future<void>> tasks;
    constexpr int NUM_TASK = 3;

    for(int i = 0; i< NUM_TASK; ++i)
    {
        tasks.push_back(std::async(std::launch::async, &Worker, std::ref(up_ios)));
    }
    std::cout << "Task size " << tasks.size() << '\n';
    std::this_thread::sleep_for(500ms);
    OrderedInvocation(up_strand);

    up_work.reset();

    for(auto &t: tasks){ t.get(); }
    return 0;
}

问题是:当我运行代码时,函数PrintNum似乎仅在单个线程上运行

控制台输出为

[140180645058368] section 4 started ...
Task size 3
[140180610144000]  Started...
[140180626929408]  Started...
[140180618536704]  Started...
[140180610144000] 1
[140180610144000] 2
[140180610144000] 3
[140180610144000] 4
[140180610144000] 5
[140180610144000] 6
[140180610144000] 7
[140180610144000] 8
[140180610144000] 9
[140180610144000]  End
[140180626929408]  End
[140180618536704]  End

我的问题是,我是否需要配置链以使任务传播到所有线程?还是我错过了这里的东西?

[编辑] 理想情况下,输出应类似于

[00154F88] The program will exit when all work has finished.
[001532B0] Thread Start
[00154FB0] Thread Start
[001532B0] x: 1
[00154FB0] x: 2
[001532B0] x: 3
[00154FB0] x: 4
[001532B0] x: 5
[00154FB0] Thread Finish
[001532B0] Thread Finish
Press any key to continue . . .

在预期的输出中,线程00154FB0001532B0都执行了PrintNum(),但在修改后的版本中,只有一个线程执行了PrintNum()。

如果未使用该链,则输出为:

[140565152012096] section 4 started ...
[140565133883136]  Started...
Task size 3
[140565117097728]  Started...
[140565125490432]  Started...
[[140565133883136] [140565117097728]] 12

3
[140565133883136] [4
[140565117097728140565125490432] 6
] 5
[140565133883136] 7
[140565125490432] 8
[140565117097728] 9
[140565125490432]  End
[140565117097728]  End
[140565133883136]  End

谢谢

这是我正在使用的计算机上的CPU信息

$lscpu
Thread(s) per core:  1
Core(s) per socket:  4
Socket(s):           1

操作系统为Ubuntu 18.04

1 个答案:

答案 0 :(得分:0)

这就是strand的目的:

  

一条链定义为事件处理程序的严格顺序调用(即无并发调用)。使用绞线可以在多线程程序中执行代码,而无需显式锁定(例如,使用互斥锁)。

如果要并行调用,则需要删除该链,将post()直接移到io_service并从多个线程中调用io_service::run(您已经在这样做了)。

不相关的注释:传递唯一的指针是没有意义的;使您的生活更轻松,只需传递原始指针或引用即可。