boost asio 疑问 - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
wisefree
V2EX    C++

boost asio 疑问

  •  
  •   wisefree 2024-02-15 17:40:24 +08:00 2202 次点击
    这是一个创建于 602 天前的主题,其中的信息可能已经有所发展或是发生改变。

    最近在看 asio 的帮助文档,看到了官方的 demo ,请问大家 conn 的引用计数增加为什么是 1 ,2 ,3 ,4 呢?

    std::cout << "3: " << new_connection.use_count() << std::endl; 

    bind 可以增加引用计数的话,这个位置 conn 的引用数应该是 2 吧,因为 start_accept 运行完毕后,引用计数要减 1

     // // server.cpp // ~~~~~~~~~~ // // Copyright (c) 2003-2023 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // #include <ctime> #include <iostream> #include <string> #include <boost/bind/bind.hpp> #include <boost/shared_ptr.hpp> #include <boost/enable_shared_from_this.hpp> #include <boost/asio.hpp> using boost::asio::ip::tcp; std::string make_daytime_string() { using namespace std; // For time_t, time and ctime; time_t now = time(0); return ctime(&now); } class tcp_connection : public boost::enable_shared_from_this<tcp_connection> { public: typedef boost::shared_ptr<tcp_connection> pointer; static pointer create(boost::asio::io_context& io_context) { return pointer(new tcp_connection(io_context)); } tcp::socket& socket() { return socket_; } void start() { message_ = make_daytime_string(); boost::asio::async_write(socket_, boost::asio::buffer(message_), boost::bind(&tcp_connection::handle_write, shared_from_this(), boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred)); } ~tcp_connection() { std::cout << "conn descontruct" << std::endl;} private: tcp_connection(boost::asio::io_context& io_context) : socket_(io_context) { } void handle_write(const boost::system::error_code& /*error*/, size_t /*bytes_transferred*/) { } tcp::socket socket_; std::string message_; }; class tcp_server { public: tcp_server(boost::asio::io_context& io_context) : io_context_(io_context), acceptor_(io_context, tcp::endpoint(tcp::v4(), 13)) { start_accept(); } private: void start_accept() { tcp_connection::pointer new_cOnnection= tcp_connection::create(io_context_); std::cout << "1: " << new_connection.use_count() << std::endl; acceptor_.async_accept(new_connection->socket(), boost::bind(&tcp_server::handle_accept, this, new_connection, boost::asio::placeholders::error)); std::cout << "2: " << new_connection.use_count() << std::endl; } void handle_accept(tcp_connection::pointer new_connection, const boost::system::error_code& error) { std::cout << "3: " << new_connection.use_count() << std::endl; if (!error) { new_connection->start(); } start_accept(); std::cout << "4: " << new_connection.use_count() << std::endl; } boost::asio::io_context& io_context_; tcp::acceptor acceptor_; }; int main() { try { boost::asio::io_context io_context; tcp_server server(io_context); io_context.run(); } catch (std::exception& e) { std::cerr << e.what() << std::endl; } return 0; } 
    1. 编译完成,运行程序
    2. 新开一个终端,运行 nc 127.0.0.1 13

    输出为:

    1: 1 2: 2 3: 3 1: 1 2: 2 4: 4 conn descontruct 
    6 条回复    2024-10-16 12:51:59 +08:00
    byaiu
        1
    byaiu  
       2024-02-15 21:00:19 +08:00   1
    tcp_connection::start 里的 shared_from_this 给 use_count 加了 1.
    同时,start_acept 里是另一个新的 tcp_connection ,和 tcp_server::handle_accept 里的 new_connection 不是一个。
    wisefree
        2
    wisefree  
    OP
       2024-02-16 08:32:56 +08:00
    @byaiu 也解释不了
    ``` c++
    std::cout << "3: " << new_connection.use_count() << std::endl;
    ```

    刚创建 conn ,引用计数是 1

    bind 后,引用计数是 2

    start_accept 运行结束,引用计数减 1 ,那么引用计数是 1

    handle_accept 中,函数参数拷贝,引用计数加 1 ,那么引用计数应该是 2 ,而不是 3
    cnbatch
        3
    cnbatch  
       2024-02-16 15:55:50 +08:00   1
    这是 boost 的“锅”/ bug 。

    把 boost 组件换成 C++11 的相同组件和纯 asio ,得到如下结果:

    1: 1
    2: 2
    3: 2
    1: 1
    2: 2
    4: 3
    conn descontruct
    cnbatch
        4
    cnbatch  
       2024-02-16 16:00:09 +08:00   1
    如果 OP 想自己做替换,基本上删掉 boost 前缀或者替换成 std 命名空间就行。有几个特殊地方除外:

    boost::asio::placeholders::error
    boost::asio::placeholders::bytes_transferred
    按顺序替换成
    std::placeholders::_1
    std::placeholders::_2

    以及
    boost::system::error_code 替换成 std::error_code
    wisefree
        5
    wisefree  
    OP
       2024-02-16 17:43:07 +08:00
    @cnbatch 太感谢了!昨天运行的时候,真是百思不得其解
    xfn
        6
    xfn  
       358 天前
    最近也在看 asio ,偶然看到楼主的问题,说一下的我理解吧。我觉得这里并不能说是 boost 的 bug ,只能说是不同版本 boost/asio 的实现细节差异。因为最终 tcp_connection 还是销毁了(从输出的“conn descontruct”可以看到),所以从结果上看行为是正确的,也没有内存泄漏。但不同版本的 boost 内部实现可能不一样,某个版本的 asio 在触发回调时内部 shared_ptr 可能会被多复制一次,导致看到的计数会不一样,但是只要最后结果符合预期,这个行为就是对的。
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     866 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 25ms UTC 21:44 PVG 05:44 LAX 14:44 JFK 17:44
    Do have faith in what you're doing.
    ubao snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86