同步:假如我想对一个文件(socket也同理)进行处理,那么通常的流程就是:git
1 fstream file; 2 file.open(); 3 file.read(); 4 //do something 5 file.close();
一般状况下,当这个线程运行到read()时会被阻塞,直到文件读取完成。github
异步:数据结构
仍是上面的代码,我在read()时经过操做系统或库提供的异步机制,告诉操做系统我想读一个文件,数据读完后执行某个功能;而当前线程在交代完操做系统该作什么工做以后,还能够作些别的事情(线程没必要等待文件IO完成)。负载均衡
为了不IO阻塞线程致使程序无响应,彻底能够为每个文件操做建立一个线程,这样就能够同时处理多个文件了。可是建立线程,切换线程,销毁线程也是一笔资源开销,若是想重复使用已有的线程,就可使用线程池。做为线程池,至少要提供建立线程和提交任务的功能,复杂一点能够智能控制线程池里的线程数量,还应该具备基本的负载均衡功能。这个文件系统中就会使用线程池。Windows API中的ThreadPool就很好用,但既然是造轮子,那么为了造轮子而造轮子也没什么关系,干脆就写个简单的线程池出来。异步
这个模块只使用stl 和boost 两个库。socket
stl主要涉及容器和fstream。boost涉及到智能指针shared_ptr,线程同步shared_mutex,lock_guard, boost::filesystem中的path和一些文件操做,线程操做建立退出等。async
自古以来内存管理都是C/C++中的重头戏,智能指针的功能就是分配出来的内存由库管理,若是某个智能指针指向的内存,经过其余的智能指针也能访问到(即有多个引用),那么该智能指针即时被销毁,指向的内存也不会销毁;只有这块内存没有引用,才会被库释放。分布式
这个库提供了一些跨平台文件操做的API,如文件夹遍历,查看属性,删除文件等。path类能够记录跨平台的路径。函数
AsyncStatus是异步IO中须要实现的功能。像读,写,放弃异步操做,错误处理等。ui
ErrorCode会出如今回调函数中,表示以前异步读写的结果,如正在处理,出错,EOF等。
FS_Handle_ST:这个结构体对应一个文件路径。在系统中每一个handle都是惟一的,系统有一个map,经过handle能够找到它对应的路径。
FS_AsyncHandle_ST:标识某个handle须要执行的任务,每一个AsyncHandle都须要指定status即任务。一个handle能够有多个异步任务,但多个任务在系统中按照队列顺序执行。
1 enum QueueOperation { PUSH_BACK, PUSH_FRONT }; 2 enum AsyncStatus { NONE, APPEND_WRITE, WRITE, READ, READ_ALL, ABORT, ERROR, EXIT }; 3 enum ErrorCode { DONE, PENDING, END_OF_FILE, OPEN_FAIL, BAD_STREAM, IO_FAIL, UNKNOWN_ERROR }; 4 5 typedef uintmax_t FS_Handle; 6 typedef uintmax_t FS_AsyncHandle; 7 8 struct FS_AsyncHandle_ST { 9 FS_Handle fileHandle = 0; 10 FS_AsyncHandle asyncHandle = 0; 11 AsyncStatus status = AsyncStatus::NONE; 12 }; 13 14 struct FS_Handle_ST { 15 FS_Handle handle = 0; 16 boost::filesystem::path fullPath; 17 };
回调函数:异步操做完成以后要作什么。使用的时候把功能在派生类里实现,重载虚函数run就能够了。
1 class FileSystemIOCallback { 2 public: 3 void operator=(const FileSystemIOCallback & cb) { 4 //.. 5 } 6 7 FileSystemIOCallback(const FileSystemIOCallback & cb) { 8 //.. 9 } 10 11 FileSystemIOCallback() { 12 //... 13 } 14 15 virtual ~FileSystemIOCallback() { 16 17 } 18 19 virtual void run(const FS_AsyncHandle_ST & ast, ErrorCode e, void * data, uintmax_t count) { 20 //... 21 } 22 };
fstream中有一个很是有趣的函数,readsome()方法,这个方法提出的目的是尽量减小同步读取的阻塞时间。该方法会读取fstream内部缓冲区里的数据,读取的字节数取决于fstream内部缓冲区和做为参数传递给它的缓冲区的大小。举个例子,若是fstream缓冲区里只有10字节,我参数给出的缓冲区大小为100字节,无论这个文件后面还有没有数据,它只会去读10个字节。操做系统和函数库可能会使用由硬件引起的中断来读取数据,运行原理相似,但其具体实现未知,还要进一步了解。
既然IO操做要阻塞线程很长一段时间,那么就把IO操做扔给线程或纤程,主线程只负责提交任务。