asio C++ library核心理念和功能(二)

2018-05-31  本文已影响0人  山羊歌的演唱会

1.2.3 线程和Asio

线程安全
一般来说,并发使用不同的对象是安全的,使用单个对象是不安全的。 但是,像io_service这样的类型可以更有力地保证可以同时使用单个对象。

线程池
多线程可能会调用io_service :: run()来设置线程池,从中可以调用完成处理程序。 这种方法也可以与io_service :: post()一起使用,以便在线程池中执行任何计算任务。
请注意,所有已加入io_service池的线程都被认为是等同的,并且io_service可以以任意方式在他们之间分配工作。

内部线程
针对特定平台的这个库的实现可以利用一个或多个内部线程来模拟异步性。尽可能地,这些线程必须对库用户不可见。 特别是,线程:

1.2.4 链:使用线程而不显式锁定

链被定义为事件处理程序的严格顺序调用(即无并发调用)。 链的使用允许执行代码在多线程程序中,而不需要显式锁定(例如使用互斥锁)。
链可以是隐含的也可以是明确的,如以下替代方法所示:

struct my_handler
{
void operator()() { ... }
};
template<class F>
void asio_handler_invoke(F f, my_handler*)
{
// Do custom invocation here.
// Default implementation calls f();
}

io_service :: strand :: wrap()函数创建了一个新的完成处理程序,它定义了asio_handler_invoke,以便函数对象通过该线程执行。

1.2.5 缓冲区

从根本上讲,I / O涉及将数据传入和传出连续的内存区域,称为缓冲区。 这些缓冲区可以简单地表示为由指针和字节大小组成的元组。 但是,为了开发高效的网络应用程序,Asio支持分散 - 集中操作。 这些操作涉及一个或多个缓冲区:

typedef std::pair<void*, std::size_t> mutable_buffer;
typedef std::pair<const void*, std::size_t> const_buffer;

这里,一个mutable_buffer可以转换为一个const_buffer,但是逆向的转换是无效的。
但是,Asio并没有按原样使用上述定义,而是定义了两个类:mutable_buffer和const_buffer。
这些目标是提供对连续内存的不透明表示,其中:

流缓冲用于集成IOSTREAMS
类asio :: basic_streambuf源自std :: basic_streambuf,用于将输入序列和输出序列与某个字符数组类型的一个或多个对象相关联,这些对象的元素存储任意值。 这些字符数组对象是streambuf对象的内部对象,但提供对数组元素的直接访问以允许它们与I / O操作一起使用,例如套接字的发送或接收操作:

缓冲区序列的顺序遍历
buffers_iterator <>类模板允许缓冲区序列(即满足MutableBufferSequence或ConstBufferSequence要求的类型)遍历,就像它们是连续的字节序列一样。 还提供了名为buffers_begin()和buffers_end()的辅助函数,其中会自动推导出buffers_iterator <>模板参数。
作为一个例子,为了从一个套接字读入一个单行并写入一个std :: string,你可以这样写:

asio::streambuf sb;
...
std::size_t n = asio::read_until(sock, sb, ’\n’);
asio::streambuf::const_buffers_type bufs = sb.data();
std::string line(
asio::buffers_begin(bufs),
asio::buffers_begin(bufs) + n);

缓冲区调试
某些标准库实现(如Microsoft Visual C ++ 8.0及更高版本附带的标准库实现)提供了称为迭代器调试的功能。 这意味着在运行时检查迭代器的有效性。 如果程序试图使用已经失效的迭代器,则会触发断言。 例如:

std::vector<int> v(1)
std::vector<int>::iterator i = v.begin();
v.clear(); // invalidates iterators
*i = 0; // assertion!

Asio利用此功能来添加缓冲区调试。 考虑下面的代码:

void dont_do_this()
{
std::string msg = "Hello, world!";
asio::async_write(sock, asio::buffer(msg), my_handler);
}

在调用异步读或写时,需要确保操作的缓冲区有效,直到调用完成处理程序。在上面的例子中,缓冲区是std :: string变量msg。这个变量在堆栈中,所以就这样了
在异步操作完成之前超出范围。如果你很幸运,那么应用程序会崩溃,但随机失败更可能。
启用缓冲区调试时,Asio会将迭代器存储到字符串中,直到异步操作完成,然后将其解引用以检查其有效性。在上面的例子中,你会在Asio尝试调用完成处理程序之前观察断言失败。
当定义_GLIBCXX_DEBUG时,此功能会自动提供给Microsoft Visual Studio 8.0或更高版本以及GCC。这种检查有一个性能成本,所以缓冲区调试只能在调试版本中启用。对于其他编译器,可以通过定义ASIO_ENABLE_BUFFER_DEBUGGING来启用。它也可以通过定义ASIO_DISABLE_BUFFER_DEBUGGING来显式禁用。

上一篇 下一篇

猜你喜欢

热点阅读