4

我正在学习使用 Boost ASIO。这是从与 Boost ASIO 文档一起给出的聊天示例中复制的一些代码,

typedef std::deque<chat_message> chat_message_queue;

class chat_client
{
    public:
        chat_client(boost::asio::io_service& io_service,
                tcp::resolver::iterator endpoint_iterator)
            : io_service_(io_service),
            socket_(io_service)
    {
        boost::asio::async_connect(socket_, endpoint_iterator,
                boost::bind(&chat_client::handle_connect, this,
                    boost::asio::placeholders::error));
    }

        void write(const chat_message& msg)
        {
            io_service_.post(boost::bind(&chat_client::do_write, this, msg));
        }

        void close()
        {
            io_service_.post(boost::bind(&chat_client::do_close, this));
        }

    private:

        void handle_connect(const boost::system::error_code& error)
        {
            //Implementation
        }

        void handle_read_header(const boost::system::error_code& error)
        {
            //Implementation
        }

        void handle_read_body(const boost::system::error_code& error)
        {
            //Implementation
        }

        void do_write(chat_message msg)
        {
            bool write_in_progress = !write_msgs_.empty();
            write_msgs_.push_back(msg);
            if (!write_in_progress)
            {
                boost::asio::async_write(socket_,
                        boost::asio::buffer(write_msgs_.front().data(),
                            write_msgs_.front().length()),
                        boost::bind(&chat_client::handle_write, this,
                            boost::asio::placeholders::error));
            }
        }



        void handle_write(const boost::system::error_code& error)
        {
            //Implementation
        }

        void do_close()
        {
            socket_.close();
        }

    private:
        boost::asio::io_service& io_service_;
        tcp::socket socket_;
        chat_message read_msg_;
        chat_message_queue write_msgs_;
};
  1. 写入是异步的,并且不使用成员变量write_msgs_read_msgs_. 这里不应该存在并发问题吗?

  2. post从运行的线程调用是否安全io_service::run?dispatch?从未运行的线程中进行相同的调用怎么样io_service::run

  3. doSend(),为什么他们将消息推送到write_msgs_而不是直接发送?同样在同一个函数中,他们为什么要检查是否write_msgs_为空,只有在不是时才继续发送?是否write_msgs_.empty() = false意味着正在写入?如何?

  4. 如果do_write()仅在一个线程中调用,那么为什么我需要一个队列来维护一系列发送?不会io_service完成手头的任务然后执行调用的异步操作do_write吗?在上面提到的示例中使用 adispatch而不是会有所不同吗?post

4

1 回答 1

8
  1. 尽管写入是异步的,但这里没有多线程:do_write()在一个线程中调用。当然,在调用完成处理程序之前,正在发送的缓冲区必须是活动的并且不变。

  2. 从任何线程调用 post() 和 dispatch() 都是安全的。阅读io_service 文档的“线程安全”部分。

  3. 如果async_write正在进行中,并且您async_write再次调用同一个套接字,则发送数据的顺序是未定义的。换句话说,数据将被弄乱。解决此问题的最简单方法是创建一个消息队列:每次async_write完成时,发出另一个async_write. (顺便说一句,这同样适用于async_read。)为什么write_msgs_.empty() = false意味着正在写入?因为只要 aswrite_msgs_不为空,handle_write(前一个的完成处理程序async_write)就会发出另一个async_write. write_msgs_此循环在为空时中断。

  4. 请阅读文档中有关 async_write 的内容

    此操作通过对流的 async_write_some 函数的零次或多次调用来实现,称为组合操作。程序必须确保流不执行其他写入操作(例如 async_write、流的 async_write_some 函数或执行写入的任何其他组合操作),直到此操作完成。

至于dispatchvs post- 据我所知,在上面的示例中它们是可以互换的。如果我们不希望被发布的仿函数被同步调用,那么使用 post 是必不可少的。

于 2012-07-18T08:23:21.763 回答