在 CPU 的全部指令中,有些指令是很是危險的,若是錯用,將致使系統崩潰,好比清內存、設置時鐘等。若是容許全部的程序均可以使用這些指令,那麼系統崩潰的機率將大大增長。因此,CPU 將指令分爲特權指令和非特權指令,對於那些危險的指令,只容許操做系統及其相關模塊使用,普通應用程序只能使用那些不會形成災難的指令。linux
當進程運行在內核空間時就處於內核態,而進程運行在用戶空間時則處於用戶態。windows
在內核態下,進程運行在內核地址空間中,此時 CPU 能夠執行任何指令。運行的代碼也不受任何的限制,能夠自由地訪問任何有效地址,也能夠直接進行端口的訪問。
在用戶態下,進程運行在用戶地址空間中,被執行的代碼要受到 CPU 的諸多檢查,它們只能訪問映射其地址空間的頁表項中規定的在用戶態下可訪問頁面的虛擬地址,且只能對任務狀態段(TSS)中 I/O 許可位圖(I/O Permission Bitmap)中規定的可訪問端口進行直接訪問。服務器
對於 Linux 來講,經過區份內核空間和用戶空間的設計,隔離了操做系統代碼(操做系統的代碼要比應用程序的代碼健壯不少)與應用程序代碼。即使是單個應用程序出現錯誤也不會影響到操做系統的穩定性,這樣其它的程序還能夠正常的運行(Linux 但是個多任務系統啊!)。網絡
因此,區份內核空間和用戶空間本質上是要提升操做系統的穩定性及可用性。併發
每一個處理器在任何指定時間點上的活動歸納爲下列三者之一:框架
以上三點幾乎包括全部的狀況,好比當 CPU 空閒時,內核就運行一個空進程,處於進程上下文,但運行在內核空間。異步
一些對外圍設備的訪問操做好比硬盤、網卡都只能運行在內核態,此外進程調度、TCP/IP協議棧等也只能工做在內核態。socket
文件描述符是一個非負整數,實際上,他是一個索引值,指向內核爲每個進程所維護的該進程打開文件的記錄表,當程序打開一個現有文件或者建立一個新文件時,內核向進程返回一個文件描述符。當咱們的進程想要對文件進行讀寫的時候,就會傳遞這個文件描述符給內核空間,內核就會根據不一樣類型的IO對相應的數據進行操做返回。 用戶進程若是想要從外圍設備(這裏以socket爲例)讀取數據,須要首先通過內核,那這裏就涉及到和內核的通訊問題了。
高併發
好比說網絡io,當咱們須要去獲取一個網頁的數據返回的時候,若是服務器無返回的時候,就會一直阻塞等待數據返回。這樣cpu的浪費就很嚴重。編碼
用戶進程想要讀取數據了,因而就經過執行recvfrom來進行一次系統調用,進入內核態,內核態若是數據沒有準備好就直接返回一個沒有準備好的標誌,咱們這邊的用戶進程也沒有閒着,就去幹別的事了,(可是後面的執行須要用到數據的話,那麼仍是要等待數據返回)可是仍是會定時輪詢系統調用查看數據是否準備好
前面的前面兩種方式一個進程只能監聽一個返回狀態,但select能夠同時監聽多個返回狀態,好比同時發起100個socket,一旦有一個數據返回了就去當即處理。因此說效率大大提升了。可是將數據從內核複製到用戶控件這個時間仍是有浪費。
獲得數據以後,操做系統會將數據從內核複製到用戶空間以後,再給信號處理程序發起數據。少了中間拷貝數據的過程,是操做系統準備好了以後再發給用戶進程的。異步io在io複用的基礎上沒有太大的提高, 可是編碼難度複雜,因此現在不少程序的框架仍是普遍使用的仍是io複用。
分析:epoll不必定就比select好,