提高:: ASIO :: deadline_timer :: async_wait不触发回调 [英] boost::asio::deadline_timer::async_wait not firing callback

查看:1069
本文介绍了提高:: ASIO :: deadline_timer :: async_wait不触发回调的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个提升 io_service对象运行在一个线程中,我想6秒后某个事件发生到客户端火在该线程回调,并重置该客户端的计时器,如果它已经在运行。

I have a boost io_service running in a thread, and I would like to fire a callback in that thread 6 seconds after a certain event happens to a client, and reset the timer for that client if it is already running.

我保持了 unordered_map<字符串的shared_ptr< deadline_timer>方式> 为每个客户端的定时器

I maintain a unordered_map<string, shared_ptr<deadline_timer>> with a timer for each client.

不过,在设置 async_wait ,我的回调不火的时间获分配金额后( io_service对象 IS运行),它也不火(有错误code)当我复位指针(它应该调用析构函数为现有的定时器,使其发布到服务)。我该如何解决这个问题?

However, upon setting async_wait, my callback does not fire after the alloted amount of time (the io_service IS running), neither does it fire (with an error code) when I reset the pointer (which should call the destructor for the existing timer, causing it to post to the service). How can I fix this?

这是我的code的相关部分:

This is the relevant part of my code:

auto it = timersByClientId.find(clientId);
if (it == timersByClientId.end())
{
    onLogonChangeCallback(clientId, true);
    timersByClientId[clientId].reset(
        new boost::asio::deadline_timer(replyService, boost::posix_time::seconds(6))
    );
    it = timersByClientId.find(clientId);
}
else
{
    // Cancel current wait operation (should fire the callback with an error code)
    it->second.reset(
        new boost::asio::deadline_timer(replyService, boost::posix_time::seconds(6))
    );
}
it->second->async_wait([this, clientId](const boost::system::error_code& err) {
    if (!err)
    {
        onLogonChangeCallback(clientId, false);
    }
});

如果它改变任何东西,我在Visual C ++ 2010运行并提高1.47.0。

If it changes anything, I'm running under Visual C++ 2010 and boost 1.47.0.

推荐答案

您code /外观/没关系十岁上下。

Your code /looks/ okay-ish.

我不知道你是如何达成的结论是,你的完成处理程序不会的[...]火(有错误code)当我复位指针的。您忽略此情况下(没有在拉姆达没有其他分支)。

I'm not sure how you are reaching the conclusion that your completion handler doesn't "[...] fire (with an error code) when I reset the pointer". You are ignoring this case (there is no else branch in the lambda).

如何更清晰地写什么逻辑?

How about writing the logic more clearly?

void foo(int clientId) {
    shared_timer& timer = timersByClientId[clientId];

    if (!timer) 
        onLogonChangeCallback(clientId, true);

    timer = make_timer(); // reset

    timer->async_wait([this, clientId](const boost::system::error_code& err) {
        if (!err)
            onLogonChangeCallback(clientId, false);
    });
}

下面是一个完整的演示与其他分支,让你看到是怎么回事。我以为1服务线程。

Here's a full demo with that else branch to let you see what is going on. I assumed 1 service thread.

看它的 住在Coliru

See it Live On Coliru.

测试负载是在0.5秒〜16账户100届活动。总运行时间为1.5秒〜因为我已经减少了会话有效期从6秒到1秒的Coliru。

The test load is 100 session activities on 16 accounts in ~0.5s. The total running time is ~1.5s because I have reduced the session expiration from 6s to 1s for Coliru.

如果你不想LogonManager的析构函数等待所有会话到期,然后加入后台线程之前清除会话表:

If you didn't want the destructor of LogonManager to wait for all sessions to expire, then clear the session table before joining the background thread:

~LogonMonitor() {
    work = boost::none;
    timersByClientId.clear();
    background.join();
}

完整列表

#include <boost/asio.hpp>
#include <boost/thread.hpp>
#include <boost/optional.hpp>
#include <boost/make_shared.hpp>

struct LogonMonitor {
    LogonMonitor() 
        : work(io_service::work(replyService)), background([this]{ replyService.run(); })
    { }

    ~LogonMonitor() {
        work = boost::none;
        // timersByClientId.clear();
        background.join();
    }

    void foo(int clientId) {
        shared_timer& timer = timersByClientId[clientId];

        if (!timer) 
            onLogonChangeCallback(clientId, true);

        timer = make_timer(); // reset

        timer->async_wait([this, clientId](const boost::system::error_code& err) {
            if (!err)
                onLogonChangeCallback(clientId, false);
            else
                std::cout << "(cancel " << clientId << " timer)" << std::endl;
        });
    }

  private:
    using io_service   = boost::asio::io_service;
    using timer        = boost::asio::deadline_timer;
    using shared_timer = boost::shared_ptr<timer>;

    io_service replyService;
    boost::optional<io_service::work> work;
    boost::thread background;

    std::map<int, shared_timer> timersByClientId;

    shared_timer make_timer() { 
        return boost::make_shared<timer>(replyService, boost::posix_time::seconds(/*6*/1)); 
    }

    void onLogonChangeCallback(int clientId, bool newLogon) 
    {
        std::cout << __FUNCTION__ << "(" << clientId << ", " << newLogon << ")" << std::endl;
    }
};

int main()
{
    LogonMonitor instance;
    for (int i = 0; i < 100; ++i)
    {
        instance.foo(rand() % 16);
        boost::this_thread::sleep_for(boost::chrono::milliseconds(rand() % 10));
    }
}

这篇关于提高:: ASIO :: deadline_timer :: async_wait不触发回调的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆