同步:假如我想對一個文件(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操做扔給線程或纖程,主線程只負責提交任務。