2012-02-29 149 views
4

我正在嘗試使用select函數來接受輸入,但如果用戶沒有輸入任何內容,則每2秒鐘執行一次其他操作。下面的代碼在第一次到達select()時等待兩秒鐘,但是一旦它打印出第一個「超時」消息,它就會在不等待2秒的情況下快速地打印出「超時」,基本上進入無限循環。任何人都知道問題是什麼?謝謝你的幫助。C++ select()不等待超時時間

#include <stdio.h> 
#include <sys/time.h> 
#include <sys/types.h> 
#include <unistd.h> 
using namespace std; 

const int STDIN = 0; 
int main(int argc, int *argv[]) 
{ 
struct timeval tv; 
fd_set readfds, master; 
tv.tv_sec = 2; 
tv.tv_usec = 0; 
FD_ZERO(&readfds); 
FD_ZERO(&master); 
FD_SET(STDIN, &readfds); 
FD_SET(STDIN, &master); 
string buffer = ""; 
while(buffer != "quit"){ 
    readfds = master; 
    if(select(STDIN+1, &readfds, NULL, NULL, &tv) == -1) perror("select"); 
    if (FD_ISSET(STDIN, &readfds)){ 
     getline(cin, buffer); 
     cout << "You entered: " << buffer << endl; 
    }else 
     cout << "Timed out.\n" << endl; 
} 
return 0; 
} 

回答

11

每個人:select()可能會更新timeout參數以指示剩餘的時間。 pselect()不會改變這個參數。

這意味着,如果超時2秒後它可以將您的tv_sec設置爲0

如果兩個timeval中的字段爲0,將立即返回。

嘗試在while()的每個循環內設置您的超時,以確保它不會被覆蓋。

1

如果你讀過Linux內核select.c的來源,你會發現,在select()調用,最後一個參數超時將在使用後設置爲零。

因此,您應該在每次調用select()之前在循環內設置電視的值。

0

如果有內存服務,對select()的調用可以更改tv的值以指示剩餘時間。您應在每次致電select()前重新初始化tv

1

你必須把

FD_ZERO(&readfds); 
FD_SET(STDIN, &readfds); 

到你的循環。指定:readfds = master;不會總是有效(實際上我很確定它不會在每個平臺上都有效 - 這取決於fd_et的定義)。 也設置tv在一個循環中是一個好主意。

+0

他可以使用'memcpy'來複制'fd_set'。每次調用select時,必須逐位重做fd集合並不是一個好主意。 – 2012-02-29 07:02:13

+0

您應該更喜歡使用FD_COPY而不是memcpy。 – 2013-02-13 15:01:15

2

我會根據您的代碼做一些更改,selecttv將被更改。

#include <stdio.h> 
#include <sys/time.h> 
#include <sys/types.h> 
#include <unistd.h> 
#include <string.h> 
#include <iostream> 
using namespace std; 

const int STDIN = 0; 
int main(int argc, int *argv[]) 
{ 
     struct timeval tv,tv1; 
     fd_set readfds, master; 
     tv.tv_sec = 2; 
     tv.tv_usec = 0; 
     FD_ZERO(&readfds); 
     FD_ZERO(&master); 
     FD_SET(STDIN, &readfds); 
     FD_SET(STDIN, &master); 
     string buffer = ""; 
     while(buffer != "quit"){ 
       readfds = master; 
       memcpy(&tv1, &tv, sizeof(tv)); 
       if(select(STDIN+1, &readfds, NULL, NULL, &tv1) == -1) perror("select"); 
       if (FD_ISSET(STDIN, &readfds)){ 
         getline(cin, buffer); 
         cout << "You entered: " << buffer << endl; 
       }else 
         cout << "Timed out.\n" << endl; 
     } 
     return 0; 
}