ISE -- I/O Buffer 之 STL vector学习
2017-06-15 13:50
106 查看
0x01 缘起
在高性能服务器开发的过程中,良好的IO缓存是整个设计比较重要的环节。带着这方面的兴趣,阅读了开源ISE的IO Buffer设计,不评估其优劣,纯粹学习这方面知识,深度学习下STL vector容器的使用和内存的管理。
0x02 IO Buffer介绍
消息缓存,主要存储socket接收和发送的消息。发送消息时,将消息有序的缓存到buffer中;消息接收时,将消息存放在缓存中,进行拼包,还原出完整的消息。0x03 ISE IO Buffer
/////////////////////////////////////////////////////////////////////////////// // class IoBuffer - 输入输出缓存 // // +-----------------+------------------+------------------+ // | useless bytes | readable bytes | writable bytes | // | | (CONTENT) | | // +-----------------+------------------+------------------+ // | | | | // 0 <= readerIndex <= writerIndex <= size class IoBuffer { public: enum { INITIAL_SIZE = 1024 }; //Buffer初始化大小 public: IoBuffer(); ~IoBuffer(); /* const 成员函数,不能修改类成员; * 获取可以读的有效字节; * */ int getReadableBytes() const { return writerIndex_ - readerIndex_; } /* * 获取可以写的有效空间字节数; * */ int getWritableBytes() const { return (int)buffer_.size() - writerIndex_; } /* * 获取可以目前已经读取完,认为无效的空间字节数; * */ int getUselessBytes() const { return readerIndex_; } /* * 追加一个字符串对象到缓存; * */ void append(const string& str); /* * 追加一个指针对象 bytes个字节到缓存; * */ void append(const void *data, int bytes); /* * 向缓存追加 bytes 个字节并填充为'\0'; * */ void append(int bytes); /*从缓存读取 bytes 个字节数据*/ void retrieve(int bytes); /*从缓存读取全部可读数据并存入 str 中*/ void retrieveAll(string& str); /*从缓存读取全部可读数据,相当于清空*/ void retrieveAll(); /*交换一个IO缓存*/ void swap(IoBuffer& rhs); /* 获取读的起始指针 ,访问一个只读指针 */ const char* peek() const { return getBufferPtr() + readerIndex_; } private: /* 获取缓存的起始指针 */ char* getBufferPtr() const { return (char*)&*buffer_.begin(); } /* 获取写位置的起始指针 */ char* getWriterPtr() const { return getBufferPtr() + writerIndex_; } /* 扩展缓存 */ void makeSpace(int moreBytes); private: std::vector<char> buffer_; //buffer 缓存容器,内存的扩展 int readerIndex_; //读指针 int writerIndex_; //写指针 };关键代码段,内存扩展:
//----------------------------------------------------------------------------- // 描述: 扩展缓存空间以便可再写进 moreBytes 个字节 //----------------------------------------------------------------------------- void IoBuffer::makeSpace(int moreBytes) { /*如果无用的字节空间和可以写的字节空间小于需要写入的空间,就调用resize调整扩大 * vector容量,满足值的写入; * vector容量会成倍扩张,INITIAL_SIZE*2, * 并将原来的从就的地方拷贝到新的; */ if (getWritableBytes() + getUselessBytes() < moreBytes) { buffer_.resize(writerIndex_ + moreBytes); } else { /*如果大于,调整目前的位置,将内存移动一次,将全部可读数据移至缓存开始处*/ int readableBytes = getReadableBytes(); char *buffer = getBufferPtr(); memmove(buffer, buffer + readerIndex_, readableBytes); readerIndex_ = 0; writerIndex_ = readerIndex_ + readableBytes; ISE_ASSERT(readableBytes == getReadableBytes()); } }
后面将详细讲解vector扩容等知识点。
0x04 STL vector
类关键片段:
// 默认allocator为alloc, 其具体使用版本请参照<stl_alloc.h> template <class T, class Alloc = alloc> class vector { public: // 标记为'STL标准强制要求'的typedefs用于提供iterator_traits<I>支持 typedef T value_type; // STL标准强制要求 typedef value_type* pointer; // STL标准强制要求 typedef const value_type* const_pointer; // 由于vector的特性, 一般我们实作的时候都分配给其连续的内存空间, // 所以其迭代器只需要定义成原生指针即可满足需要 typedef value_type* iterator; // STL标准强制要求 typedef const value_type* const_iterator; typedef value_type& reference; // STL标准强制要求 typedef const value_type& const_reference; typedef size_t size_type; typedef ptrdiff_t difference_type; // STL标准强制要求 #ifdef __STL_CLASS_PARTIAL_SPECIALIZATION typedef reverse_iterator<const_iterator> const_reverse_iterator; typedef reverse_iterator<iterator> reverse_iterator; #else /* __STL_CLASS_PARTIAL_SPECIALIZATION */ typedef reverse_iterator<const_iterator, value_type, const_reference, difference_type> const_reverse_iterator; typedef reverse_iterator<iterator, value_type, reference, difference_type> reverse_iterator; #endif /* __STL_CLASS_PARTIAL_SPECIALIZATION */ protected: // 这个提供STL标准的allocator接口 typedef simple_alloc<value_type, Alloc> data_allocator; iterator start; // 内存空间起始点 iterator finish; // 当前使用的内存空间结束点 iterator end_of_storage; // 实际分配内存空间的结束点 void insert_aux(iterator position, const T& x); .................... }详细讲解resize函数:
void resize(size_type __new_size, const _Tp& __x) { if (__new_size < size()) erase(begin() + __new_size, end()); else insert(end(), __new_size - size(), __x); } void resize(size_type __new_size) { resize(__new_size, _Tp()); }
resize()的作用是改变vector中元素的数目:
1、如果n比当前的vector元素数目要小,vector的容量要缩减到resize的第一个参数大小,既n。并移除那些超出n的元素同时销毁他们。
2、如果n比当前vector元素数目要大,在vector的末尾扩展需要的元素数目,如果第二个参数val指定了,扩展的新元素初始化为val的副本,否则按类型默认初始化。
注意:如果n大于当前的vector的容量(是容量,并非vector的size),将会引起自动内存分配。所以现有的pointer,references,iterators将会失效。
0x05 额外补充const
1、const成员函数不允许修改它所在对象的任何一个数据成员,const成员函数能够访问对象的const成员,而其他成员函数则不可以。2、对于const类对象/指针/引用可以调用const成员函数,但是不可以调用非const类型的成员函数
相关文章推荐
- Java NIO 学习 ByteBuffer,FileChannel,Socket
- C++/GDI+ 学习笔记(四)——实用技巧——双缓冲(Double Buffer)
- Java NIO 学习笔记 - ByteBuffer
- 对PostgreSQL中bufmgr.c 的BgBufferSync的静态变量学习 --prev_strategy_buf_id
- 关于String.concat()方法和StringBuffer.append()方法的学习:方法是如何追加字符到源字符串的
- 我的安卓学习之路--String StringBuffer StringBuilder的区别
- Java nio 学习笔记(一) Buffer(缓冲区)与Channel(通道)的相关知识
- 黑马程序员_Java学习日记_JAVA中API中对象String和StringBuffer/StringBuilder
- 对Postmaster 中 bufmgr.c 的 BgBufferSync.c 中静态变量的学习理解---saved_info_valid
- C++/GDI+ 学习笔记(四)——实用技巧——双缓冲(Double Buffer)
- Google Protocol Buffer 学习
- java学习笔记(三十八)java新IO之IntBuffer
- [学习摘录]读和写,关于cache和buffer
- Java nio 学习笔记(一) Buffer(缓冲区)与Channel(通道)的相关知识
- java byteBuffer 的学习
- linux 0.11 内核学习 -- buffer.c
- NIO学习小结--Channel and Buffer
- 学习Emacs系列教程(四:Minibuffer)、(五:编辑 -2)、(六:编辑-3) 、(七:剪切板)、(八:查找替换)
- C++/GDI+ 学习笔记(六)——实用技巧——双缓冲(Double Buffer)
- Boost学习之循环缓冲区--circular_buffer