简体   繁体   English

C++中多线程联网通知的设计

[英]Design of multi-threaded networking notifications in C++

Basically there are a couple operational modes that my program can be in, each of them requiring initialization then updating.基本上,我的程序可以使用几种操作模式,每种模式都需要初始化然后更新。 Each mode has its own configuration struct.每种模式都有自己的配置结构。

How can I after receiving a message and determining what mode its describing notify the main thread to initialize then start updating that mode?在收到消息并确定其描述的模式后如何通知主线程进行初始化然后开始更新该模式? (I'm looking for an outline of the best way to do it in C++17) (我正在寻找在 C++17 中实现它的最佳方法的大纲)

To clarify, it is a daemon application.澄清一下,它是一个守护程序应用程序。 After initialization, the main thread's only job is to do the calculations required by mode updates.初始化后,主线程的唯一工作就是进行模式更新所需的计算。 The networking is done on a separate worker thread with Boost.Asio.网络是使用 Boost.Asio 在单独的工作线程上完成的。 I also expect (as I am writing the client side program as well) that the frequency of mode changes will be low (~10hz max), so I want to avoid the use of a queue since the modes are for controlling the behavior of a robot, and a queue would add latency.我还期望(因为我也在编写客户端程序)模式更改的频率会很低(最大~10hz),所以我想避免使用队列,因为模式是为了控制一个机器人,队列会增加延迟。

Assuming your main thread can just sit and wait for the network download to complete before it starts the main code, you can use a std::condition_variable假设您的主线程可以在启动主代码之前等待网络下载完成,您可以使用std::condition_variable

Your main thread does this:你的主线程这样做:

std::condition_variable cv;
std::mutex mut;
bool networkOperationCompleted;
Config globalconfig;

int main()
{
     // initialize whatever kicks off the network thread

     std::unique_lock<std::mutex> lck(mut);
     while (networkOperationCompleted == false)
     {
         cv.wait();
     }
}

meanwhile, your network thread does this:同时,您的网络线程执行以下操作:

extern std::condition_variable cv;
extern std::mutex mut;
extern bool networkOperationCompleted;
extern Config globalconfig;

void background_task()
{

     Config config;
     DownloadTheConfig(&config);
     {
         std::unique_lock<std::mutex> lck(m);
         globalConfig = config;
         networkOperationComplete = true;
         cv.notify_all();
     }
}
 

I ended up going with something like this:我最终选择了这样的东西:

class config
{
public:
    using empty = std::monostate;

    struct modeA
    {
        ...
    };

    struct modeB
    {
        ...
    };

    template<typename T, typename Lambda>
    void handle(Lambda&& handler) const
    {
        if (std::holds_alternative<T>(storage))
        {
            handler(std::get<T>(storage));
        }
    }

    void clear()
    {
        storage = empty{};
    }

private:
    std::variant<empty, modeA, modeB> storage;
};

config server::pop_cfg()
{
    std::unique_lock lock{cfg_mutex};
    config copy{cfg};
    cfg.clear();
    return copy;
}

int main()
{
    ...

    mode* mode;
    while (true)
    {
        config cfg = server.pop_cfg();
        
        cfg.handle<config::empty>([&](...) {
            mode->update();
        });
        
        cfg.handle<config::modeA>([&](config::modeA cfg) {
            mode = new ModeA(cfg);
        });
        
        cfg.handle<config::modeB>([&](config::modeB cfg) {
            mode = new ModeB(cfg);
        });
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM