【问题标题】:Design of multi-threaded networking notifications in C++C++中多线程网络通知的设计
【发布时间】:2021-12-30 06:22:42
【问题描述】:

基本上,我的程序可以使用几种操作模式,每种模式都需要初始化然后更新。每种模式都有自己的配置结构。

在收到消息并确定其描述的模式后如何通知主线程进行初始化然后开始更新该模式? (我正在寻找在 C++17 中实现它的最佳方法的大纲)

为了澄清,它是一个守护程序应用程序。初始化之后,主线程的唯一工作就是进行模式更新所需的计算。网络是使用 Boost.Asio 在单独的工作线程上完成的。我还期望(因为我也在编写客户端程序)模式更改的频率会很低(最大~10hz),所以我想避免使用队列,因为模式是为了控制一个机器人,队列会增加延迟。

【问题讨论】:

  • 可以在主线程中有一个通知队列,当收到的消息被推入队列时,使用条件变量通知主线程。
  • 如果不了解您的主线程,很难说。它有主循环、消息队列吗?等等..等等..
  • 我已经回答了,但可能有点过早。您的应用程序是带有 UI 的 GUI 程序吗?这改变了一切。或者它是一个控制台/守护进程,在后台工作完成时主线程可以保持暂停?无论如何,这个后台线程是如何开始网络的?
  • 我在问题中添加了其他信息。
  • 主线程是否在运行(控制)循环?例如。它是否有一个 while 循环来检查条件并在需要时运行其他代码?或者是什么阻止了主线程直接退出你的程序?

标签: c++ multithreading networking server


【解决方案1】:

假设您的主线程可以在启动主代码之前等待网络下载完成,您可以使用std::condition_variable

你的主线程会这样做:

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();
     }
}

同时,您的网络线程执行以下操作:

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();
     }
}
 

【讨论】:

  • 这在循环中看起来如何?我的意思是,如果我在 main() 中有一个“init(config)”和“update()”函数,我怎么能总是在配置下载时初始化并在下载另一个配置之前继续更新?循环条件是什么样的?
【解决方案2】:

我最终选择了这样的东西:

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);
        });
    }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-06-19
    • 2010-09-13
    • 1970-01-01
    • 2011-08-21
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多