asio的线程安全
疑问:
io_context::stop()的内部动作?
ip::tcp::endpoint ep(ip::tcp::v4(), port_); //没有v6或者统一版本构建address_any的方法??
ip::address::from_string("0.0.0.0");//是否可以构建统一的address_any?
ip::tcp::resolver::iterator iter = resolver.resolve( query); //如何判断失败?如何读取多个?
socket的open()操作什么意义?
sock.open(ep.protocol());
mutable_buffer ??
Boost.Asio在网络通信、COM串行端口和文件上成功地抽象了输入输出的概念。
线程安全:
io_service是线程安全的,多个线程可以同时调用io_service::run()函数。
io_service::run()函数会阻塞调用线程,直到所有回调都调用结束;
不论多少个线程调用io_service::run(),每个调用线程都会执行所有的回调;且和其他线程是并行的。
socket类不是线程安全的。不能在一个线程里读一个socket,同时在另一个线程里写这个socket。
utility类不是线程安全的。
boost.asio本身包含几个线程。只有调用了io_serivce::run()方法的线程执行回调。
io_service和线程:
1、一个io_service一个线程。
2、一个io_service多个线程(多个线程都已io_service::run作为线程函数内主循环)。
如果多个线程同时调用一个io_service的对象的run(),一个事件的回调由哪个线程执行???那个线程执行时不确定的;而一个事件的回调只会在一个线程执行,即只执行一次。比如,用这种模式处理post的异步操作时,不能保障按照post的顺序执行,而是无序的。
3、多个io_service多个线程。
多个io_service,只有一个线程;这种模式是没有意义的。
*** io_service::run()函数在没有要管理的事件时,函数就会退出。所以,需要在事件处理函数(回调函数)里再次加入监控的事件;或者采用dummy work方式: io_service::work(io_svc_obj)。
boost::asio::local:这个命名空间包含了POSIX特性的类;boost::asio::windows:这个命名空间包含了Windows特性的类。
boost asio ip address
address_v4
address_v6
tcp socket
endpoint
acceptor
reslover
iostream
udp socket
endpoint
resolver
icmp socket
endpoint
resolver
error
ssl
local
windows
buffer
streambuf
ip::tcp::socket = basic_stream_socket;
ip::udp::socket = basic_datagram_socket;
ip::icmp::socket = basic_raw_socket;
*** 所有的同步函数都有抛出异常和返回错误码两种形式的函数重载。
socket上的操作:
open(protocol):这个函数用给定的IP协议(v4或者v6)打开一个socket。你主要在UDP/ICMP socket,或者服务端socket上使用。
close():这个函数用来关闭套接字。调用时这个套接字上任何的异步操作都会被立即关闭,同时返回error::operation_aborted错误码。
shutdown(type_of_shutdown):这个函数立即使send或者receive操作失效,或者两者都失效。
cancel():这个函数取消套接字上所有的异步操作。这个套接字上任何的异步操作都会立即结束,然后返回error::operation_aborted错误码。
对于异步函数来说,处理程序的格式void handler(constboost::system::error_code& e, size_t bytes)都是一样的。
**** ip::tcp::socket 实例不支持拷贝构造和拷贝赋值。
当下面情况出现时,所有read和write操作都会结束:
可用的缓冲区满了(当读取时)或者所有的缓冲区已经被写入(当写入时)。
完成处理方法返回0(如果你提供了这么一个方法)。
错误发生时。
*** *_at方法可以支持在流上做随意读写;但socket不支持随机读写。
run_once()方法最多执行和分发一个异步操作:
1、如果没有等待的操作,方法立即返回0
2、如果有等待操作,方法在第一个操作执行之前处于阻塞状态,然后返回1。
***** 可以使用service.post()使自定义方法被异步地调用。
Boost.Asio提供了三种让你把处理方法添加为异步调用的方式:
1、service.post(handler):这个方法能确保其在请求io_service实例,然后调用指定的处理方法之后立即返回。handler稍后会在某个调用了service.run()的线程中被调用。
2、service.dispatch(handler):这个方法请求io_service实例去调用给定的处理方法,但是另外一点,如果当前的线程调用了service.run(),它可以在方法中直接调用handler。
3、service.wrap(handler):这个方法创建了一个封装方法,当被调用时它会调用service.dispatch(handler)。
io_service::strand 类(用来序列化异步调用)。
*****为了使socket和缓冲区(read或者write)在整个异步操作的生命周期中一直活动,我们需要采取特殊的防护措施。连接类需要继承自enabled_shared_from_this,然后在内部保存它需要的缓冲区,而且每次异步调用都要传递一个智能指针给this操作。
sock_.async_write_some(buffer(write_buffer_, msg.size()), boost::bind(&connection::on_write, shared_from_this(), _1, _2));
int main(int argc, char* argv[]) {
for ( int i = 0; i < 10; ++i)
service.post(boost::bind(func, i));
boost::thread_group threads;
for ( int i = 0; i < 3; ++i)
threads.create_thread(worker_thread);
//***??? 等待所有线程被创建完?
boost::this_thread::sleep( boost::posix_time::millisec(500));
threads.join_all();
}
*** 如果一个类支持了stl的stream操作,则可以把boost::asio::buffer转换成std::i/ostream实例,从而可以简单的通过流操作如 is >> obj;转换成类的对象值。在实现协议编解码时比较常用。
要调试asio:
在头文件前加入宏:
#define BOOST_ASIO_ENABLE_HANDLER_TRACKING
#include <boost/asio.hpp>
实现SSL服务端的时候,可以参考Boost.Asio一个SSL服务端的例子,你可以在boost/libs/asio/example/ssl/server.cpp中找到。
****使用io_context.post()操作,必须提前启动io_context.run()。(即让它关联一个线程,处以等待或处理任务中)。
多线程:
io_service: The io_service class is thread-safe. Several threads can call io_service::run(). Most of the time you'll probably call io_service::run() from a single thread that function is blocking until all asynchronous operations complete. However, you can call io_service::run() from several threads. This will block all threads that have called io_service::run(). All callbacks will be called in the context of any of the threads that called io_service::run(); this also means that if you call io_service::run() in only one thread, all callbacks are called in the context of that thread.
socket: The socket classes are not thread-safe. Thus, you should avoid doing such as reading from a socket in one thread and write to it in a different thread (this isn't recommended in general, let alone with Boost.Asio).
utility: For the utility classes, it usually does not make sense to be used in several threads, nor are they thread-safe. Most of them are meant to just be used for a short time, then go out of scope.
The Boost.Asio library itself can use several threads besides your own, but it guarantees that from those threads, it will not call any of your code. This in turn means that callbacks are called only from the threads that have called io_service::run().
******asio socket多线程:ssl_stream(或者ip::tcp::socket)上的异步操作(async_xxx)不能在多个线程里调用;可以使用io_context::post()操作或者strand(多线程运行同一个io_context::run()的情况下),把操作过程限制到一个线程,保障一个socket上的async_xxx操作不在多个线程调用(不可能同时被多个线程调用)。
*****async_xxx的callback一定是在运行io_service::run()的线程里调用的。
*****async_xxx的调用必须在一个线程里,即要和callback在一个线程,即要和io_service::run()一个线程。
****io_service::post()操作是依赖io_service的,不关socket的状态。
******ssl::stream的线程安全性: The application must also ensure that all asynchronous operations are performed within the same implicit or explicit strand.
如果socket及其上的操作只属于一个线程,那么其隐式拥有一个strand。