① 誰能告訴我 linux下select函數到底是干什麼用的 貌似我不用它也可以得到我想要的結果啊
select是用來設置超時時間的,其第一個參數本來是一個文件號,假如讀取該文件長時間沒有返回則超時跳出,而這部分代碼將文件號設置為0,說明只是為了控制延時不過看你這部分代碼,明顯只是實現一個比較精確定時的sleep這段代碼之所以這么做,是因為linux本身的sleep函數非常不準(windows也是一樣),在線程較多,cpu任務較重的時候,sleep函數的精確度根本無法達到要求於是你這段代碼使用select來代替sleep更為精準,其精準程度和內核相關,如果內核的滴答頻率決定的,一般是100HZ也有1000hz的(因內核版本不同而不同),也就是說select做多可以精確到10ms,或者1ms,而sleep就做不到於是這段函數最重要的作用就是用高精確的select函數來代替低精確度的sleep函數,實現時間較為精準的延時。可查閱《Linux就該這么學》了解更多Linux介紹。
② 怎樣在Linux下實現精確定時器
linux下使用select實現精確定時器
在編寫程序時,我們經常回用到定時器。本文講述如何使用select實現超級時鍾。使用select函數,我們能實現微妙級別精度的定時器。同時,select函數也是我們在編寫非阻塞程序時經常用到的一個函數。
首先看看select函數原型如下:
int select(int nfds, fd_set *readfds, fd_set *writefds,
fd_set *exceptfds, struct timeval *timeout);
參數說明:
slect的第一個參數nfds為fdset集合中最大描述符值加1,fdset是一個位數組,其大小限制為__FD_SETSIZE(1024),位數組的每一位代表其對應的描述符是否需要被檢查。
select的第二三四個參數表示需要關注讀、寫、錯誤事件的文件描述符位數組,這些參數既是輸入參數也是輸出參數,可能會被內核修改用於標示哪些描述符上發生了關注的事件。所以每次調用select前都需重新初始化fdset。
timeout參數為超時時間,該結構會被內核修改,其值為超時剩餘的時間。
利用select實現定時器,需要利用其timeout參數,注意到:
1)select函數使用了一個結構體timeval作為其參數。
2)select函數會更新timeval的值,timeval保持的值為剩餘時間。
如果我們指定了參數timeval的值,而將其他參數都置為0或者NULL,那麼在時間耗盡後,select函數便返回,基於這一點,我們可以利用select實現精確定時。
timeval的結構如下:
struct timeval{
long tv_sec;/*secons*
long tv_usec;/*microseconds*/
}
我們可以看出其精確到microseconds也即微妙。
一、秒級定時器
void seconds_sleep(unsigned seconds){
struct timeval tv;
tv.tv_sec=seconds;
tv.tv_usec=0;
int err;
do{
err=select(0,NULL,NULL,NULL,&tv);
}while(err<0 && errno==EINTR);
}
二、毫秒級別定時器
void milliseconds_sleep(unsigned long mSec){
struct timeval tv;
tv.tv_sec=mSec/1000;
tv.tv_usec=(mSec%1000)*1000;
int err;
do{
err=select(0,NULL,NULL,NULL,&tv);
}while(err<0 && errno==EINTR);
}
三、微妙級別定時器
void microseconds_sleep(unsigned long uSec){
struct timeval tv;
tv.tv_sec=uSec/1000000;
tv.tv_usec=uSec%1000000;
int err;
do{
err=select(0,NULL,NULL,NULL,&tv);
}while(err<0 && errno==EINTR);
}
現在我們來編寫幾行代碼看看定時效果吧。
#include <stdio.h>
#include <sys/time.h>
#include <errno.h>
int main()
{
int i;
for(i=0;i<5;++i){
printf("%d\n",i);
//seconds_sleep(1);
//milliseconds_sleep(1500);
microseconds_sleep(1900000);
}
}
註:timeval結構體中雖然指定了一個微妙級別的解析度,但內核支持的分別率往往沒有這么高,很多unix內核將超時值向上舍入成10ms的倍數。此外,加上內核調度延時現象,即定時器時間到後,內核還需要花一定時間調度相應進程的運行。因此,定時器的精度,最終還是由內核支持的分別率決定。
③ 關於Linux下一個小程序中select()函數的問題,這個程序中select到底執行了幾次
原因很簡單。
因為,你按下一個鍵之後,緩沖區裡面有數據了,也就是說,stdin已經發生了一個事件,就是有數據來了。
你一直沒有對緩沖區做任何操作,因此stdin一直保持著有數據的狀態。
如果你在個select返回之後,用fflush清空緩沖區,或者,把緩沖區數據用scanf,getchar等輸入函數給拿出來,數據取完了,stdin緩沖區就沒東西了,再select,狀態就是等待事件發生狀態了。
為了保險,你每次重新把tv給賦值一次.
tv.tv_sec=2;
tv.tv_usec=0;
④ Linux下select函數文件描述符狀態的問題
當然是在有輸入或者輸出時文件描述符的讀寫狀態改變咯,比如標准輸入的文件描述符是0,如果用select來等待0號文件描述符,那麼當在鍵盤上敲字元時開始,就是文件描述符的讀寫狀態改變之時,這時select函數就會返回;對於套接字描述符來說也是這樣,用select來等待一個伺服器描述符,那麼當有新的連接請求時(伺服器描述符等待請求時是一個讀描述符,當有新請求時實際上是有一個輸入),伺服器描述符的讀寫狀態改變,select函數返回。順便說一下,檢查哪個文件描述符發生改變,可以用FD_ISSET宏來進行檢測。
⑤ 關於linux中select()函數的問題
是的。程序會block在這里,也就是你說的等待。這里等待的意思是操作系統會切換到其他進程去執行。read() write()函數也同樣。不過read() write()根據參數fd的性質,可以是non_block的。這時候,如果不能寫或者沒有數據可讀,會立即出錯返回,然後程序可以去檢查errno知道發生了什麼。
⑥ Linux內核中select,poll和epoll的區別
select:
下面是select的函數介面:
int select (int n, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);
select 函數監視的文件描述符分3類,分別是writefds、readfds、和exceptfds。調用後select函數會阻塞,直到有描述副就緒(有數據 可讀、可寫、或者有except),或者超時(timeout指定等待時間,如果立即返回設為null即可),函數返回。當select函數返回後,可以 通過遍歷fdset,來找到就緒的描述符。
select目前幾乎在所有的平台上支持,其良好跨平台支持也是它的一個優點。select的一 個缺點在於單個進程能夠監視的文件描述符的數量存在最大限制,在Linux上一般為1024,可以通過修改宏定義甚至重新編譯內核的方式提升這一限制,但 是這樣也會造成效率的降低。
poll:
int poll (struct pollfd *fds, unsigned int nfds, int timeout);
不同與select使用三個點陣圖來表示三個fdset的方式,poll使用一個 pollfd的指針實現。
struct pollfd {
int fd; /* file descriptor */
short events; /* requested events to watch */
short revents; /* returned events witnessed */
};
pollfd結構包含了要監視的event和發生的event,不再使用select「參數-值」傳遞的方式。同時,pollfd並沒有最大數量限制(但是數量過大後性能也是會下降)。 和select函數一樣,poll返回後,需要輪詢pollfd來獲取就緒的描述符。
從上面看,select和poll都需要在返回後,通過遍歷文件描述符來獲取已經就緒的socket。事實上,同時連接的大量客戶端在一時刻可能只有很少的處於就緒狀態,因此隨著監視的描述符數量的增長,其效率也會線性下降。
epoll:
epoll的介面如下:
int epoll_create(int size);
int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);
typedef union epoll_data {
void *ptr;
int fd;
__uint32_t u32;
__uint64_t u64;
} epoll_data_t;
struct epoll_event {
__uint32_t events; /* Epoll events */
epoll_data_t data; /* User data variable */
};
int epoll_wait(int epfd, struct epoll_event * events, int maxevents, int timeout);主要是epoll_create,epoll_ctl和epoll_wait三個函數。epoll_create函數創建epoll文件描述符,參數size並不是限制了epoll所能監聽的描述符最大個數,只是對內核初始分配內部數據結構的一個建議。返回是epoll描述符。-1表示創建失敗。epoll_ctl 控制對指定描述符fd執行op操作,event是與fd關聯的監聽事件。op操作有三種:添加EPOLL_CTL_ADD,刪除EPOLL_CTL_DEL,修改EPOLL_CTL_MOD。分別添加、刪除和修改對fd的監聽事件。epoll_wait 等待epfd上的io事件,最多返回maxevents個事件。
在 select/poll中,進程只有在調用一定的方法後,內核才對所有監視的文件描述符進行掃描,而epoll事先通過epoll_ctl()來注冊一 個文件描述符,一旦基於某個文件描述符就緒時,內核會採用類似callback的回調機制,迅速激活這個文件描述符,當進程調用epoll_wait() 時便得到通知。
epoll的優點主要是一下幾個方面:
1. 監視的描述符數量不受限制,它所支持的FD上限是最大可以打開文件的數目,這個數字一般遠大於2048,舉個例子,在1GB內存的機器上大約是10萬左 右,具體數目可以cat /proc/sys/fs/file-max察看,一般來說這個數目和系統內存關系很大。select的最大缺點就是進程打開的fd是有數量限制的。這對 於連接數量比較大的伺服器來說根本不能滿足。雖然也可以選擇多進程的解決方案( Apache就是這樣實現的),不過雖然linux上面創建進程的代價比較小,但仍舊是不可忽視的,加上進程間數據同步遠比不上線程間同步的高效,所以也 不是一種完美的方案。
2. IO的效率不會隨著監視fd的數量的增長而下降。epoll不同於select和poll輪詢的方式,而是通過每個fd定義的回調函數來實現的。只有就緒的fd才會執行回調函數。
3.支持電平觸發和邊沿觸發(只告訴進程哪些文件描述符剛剛變為就緒狀態,它只說一遍,如果我們沒有採取行動,那麼它將不會再次告知,這種方式稱為邊緣觸發)兩種方式,理論上邊緣觸發的性能要更高一些,但是代碼實現相當復雜。
4.mmap加速內核與用戶空間的信息傳遞。epoll是通過內核於用戶空間mmap同一塊內存,避免了無畏的內存拷貝。
⑦ linux select 怎麼理解
linux select函數詳解
在Linux中,我們可以使用select函數實現I/O埠的復用,傳遞給 select函數的參數會告訴內核:
•我們所關心的文件描述符
•對每個描述符,我們所關心的狀態。(我們是要想從一個文件描述符中讀或者寫,還是關注一個描述符中是否出現異常)
•我們要等待多長時間。(我們可以等待無限長的時間,等待固定的一段時間,或者根本就不等待)
從 select函數返回後,內核告訴我們一下信息:
•對我們的要求已經做好准備的描述符的個數
•對於三種條件哪些描述符已經做好准備.(讀,寫,異常)
有了這些返回信息,我們可以調用合適的I/O函數(通常是 read 或 write),並且這些函數不會再阻塞.
#include <sys/select.h>
int select(int maxfdp1, fd_set *readset, fd_set *writeset, fd_set *exceptset,struct timeval *timeout);
返回:做好准備的文件描述符的個數,超時為0,錯誤為 -1.
首先我們先看一下最後一個參數。它指明我們要等待的時間:
struct timeval{
long tv_sec; /*秒 */
long tv_usec; /*微秒 */
}
有三種情況:
timeout == NULL 等待無限長的時間。等待可以被一個信號中斷。當有一個描述符做好准備或者是捕獲到一個信號時函數會返回。如果捕獲到一個信號, select函數將返回 -1,並將變數 erro設為 EINTR。
timeout->tv_sec == 0 &&timeout->tv_usec == 0不等待,直接返回。加入描述符集的描述符都會被測試,並且返回滿足要求的描述符的個數。這種方法通過輪詢,無阻塞地獲得了多個文件描述符狀態。
timeout->tv_sec !=0 ||timeout->tv_usec!= 0 等待指定的時間。當有描述符符合條件或者超過超時時間的話,函數返回。在超時時間即將用完但又沒有描述符合條件的話,返回 0。對於第一種情況,等待也會被信號所中斷。
⑧ linux下的select函數是幹嘛的
select是用來設置超時時間的,其第一個參數本來是一個文件號,假如讀取該文件長時間沒有返回則超時跳出,而這部分代碼將文件號設置為0,說明只是為了控制延時
不過看你這部分代碼,明顯只是實現一個比較精確定時的sleep
這段代碼之所以這么做,是因為linux本身的sleep函數非常不準(windows也是一樣),在線程較多,cpu任務較重的時候,sleep函數的精確度根本無法達到要求
於是你這段代碼使用select來代替sleep更為精準,其精準程度和內核相關,如果內核的滴答頻率決定的,一般是100HZ也有1000hz的(因內核版本不同而不同),也就是說select做多可以精確到10ms,或者1ms,而sleep就做不到
於是
這段函數最重要的作用就是用高精確的select函數來代替低精確度的sleep函數,實現時間較為精準的延時
⑨ 關於linux select函數fgets函數
操作系統知道文件描述符對應的設備是否可讀,所以實際是由內核提供系統調用來真正實現 select 的。
一般對於通過 fopen 操作的文件,我們沒必要用 select, 首先你要把 FILE * 轉成對應的文件描述符,其次對於標准文件,一般情況下讀和寫是 non-block 的,select主要是用來對那些會block的設備用的。當然你硬要這么用,也沒問題,但是 select 對於這種文件總是會返回可讀的,和緩沖區里是否有內容無關(緩沖區的實現是在用戶空間的,顯然內核不知道其狀態)。因為即使整個文件都被讀入緩沖區,由於此時描述符處於 EOF 狀態, select 仍然會返回可讀。
這里實在是有太多細節。 總之,不建議濫用select,對於標准文件或者單個設備的讀寫,完全沒意義。
⑩ linux 下 select 函數 延時的問題
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
int main()
{
int rc = 0;
struct timeval tv;
while (true)
{
tv.tv_sec = 5;
tv.tv_usec = 0;
rc = select(0, NULL, NULL, NULL, &tv);
printf("select = %d\n", rc);
}
return 0;
}