Linux Select之坑


最近在寫一個demo程序,調用select()來監聽socket狀態,流程如下:

r_set 初始化

timeout 初始化3秒超時

loop{

  select(ntfs, &r_set, null, null, &timeout)

}

然后我驚奇的發現當對端發送消息時select()只會觸發一次,當下一次再有消息傳遞過來的時候不會被觸發,后來在網上搜索了一下說是要每一次循環都要初始化一次r_set,就可以完成多次觸發了:

timeout 初始化3秒超時

loop{

  r_set 初始化

  select(ntfs, &r_set, null, null, &timeout)

}

同時超時也只有在第一次循環阻塞三秒,之后的循環完全不會阻塞,我打日志調試發現在第一次阻塞超時之后timeout 重置為 0... ...

loop{

  r_set 初始化

  timeout 初始化3秒超時

  select(ntfs, &r_set, null, null, &timeout)

}

這才是正確姿勢,但是我在網上看到很多例子並沒有重復初始化timeout,難道是我用了假select()?本着實事求是的原則我查看了一下man文檔,上面寫了這么一句話:

On Linux, select() modifies timeout to reflect the amount of time not slept; most other implementations do not do this.  (POSIX.1 permits either behavior.)  This  causes  problems  both  when Linux  code which reads timeout is ported to other operating systems, and when code is ported to Linux that reuses a struct timeval for multiple select()s in a loop without reinitializing it. Consider timeout to be undefined after select() returns.

好吧,確實很任性,但作用類似的C library 中的pselect()就不用這么做:

 C library/kernel differences
       The pselect() interface described in this page is implemented by glibc.  The underlying Linux system call is named pselect6().  This system call has somewhat different behavior from the glibc
       wrapper function.

       The Linux pselect6() system call modifies its timeout argument.  However, the glibc wrapper function hides this behavior by using a local variable for the timeout argument that is  passed  to
       the system call.  Thus, the glibc pselect() function does not modify its timeout argument; this is the behavior required by POSIX.1-2001.

       The final argument of the pselect6() system call is not a sigset_t * pointer, but is instead a structure of the form:

           struct {
               const sigset_t *ss;     /* Pointer to signal set */
               size_t          ss_len; /* Size (in bytes) of object pointed
                                          to by 'ss' */
           };

       This allows the system call to obtain both a pointer to the signal set and its size, while allowing for the fact that most architectures support a maximum of 6 arguments to a system call

它的意思是,pselect()在傳入時間參數的時候會付給一個參數temp,然后把temp傳進去,這樣就不會修改timeout參數了。

ps:

POSIX表示可移植操作系統接口(Portable Operating System Interface of UNIX,縮寫為 POSIX ),POSIX標准定義了操作系統應該為應用程序提供的接口標准,是IEEE為要在各種UNIX操作系統上運行的軟件而定義的一系列API標准的總稱,其正式稱呼為IEEE 1003,而國際標准名稱為ISO/IEC 9945。
POSIX標准意在期望獲得源代碼級別的軟件可移植性。換句話說,為一個POSIX兼容的操作系統編寫的程序,應該可以在任何其它的POSIX操作系統(即使是來自另一個廠商)上編譯執行。
POSIX 並不局限於 UNIX。許多其它的操作系統,例如 DEC OpenVMS 支持 POSIX 標准,尤其是 IEEE Std. 1003.1-1990(1995 年修訂)或 POSIX.1,POSIX.1 提供了源代碼級別的 C 語言應用編程接口(API)給操作系統的服務程序,例如讀寫文件。POSIX.1 已經被國際標准化組織(International Standards Organization,ISO)所接受,被命名為 ISO/IEC 9945-1:1990 標准。
 
最后,還有一點,在select監聽的socket,在其他線程被close()掉,select是不會收到消息的:
Multithreaded applications
       If a file descriptor being monitored by select() is closed in another thread, the result is unspecified.  On some UNIX systems, select() unblocks and returns, with an indication that the file
       descriptor  is ready (a subsequent I/O operation will likely fail with an error, unless another the file descriptor reopened between the time select() returned and the I/O operations was per‐
       formed).  On Linux (and some other systems), closing the file descriptor in another thread has no effect on select().  In summary, any application that relies on a particular behavior in this
       scenario must be considered buggy.

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM