2011-07-27 10 views
2

pthreadを使用しているものがあるかどうかを確認するために標準入力を確認しようとしています。私は(私は)これを行う必要があるので、標準で何もない場合は、ストリームアクセス関数が入力をブロックするためです。pthreadsを使用して標準入力を確認する

私はこれを行う方法は、標準入力をチェックしてスリープ(1)し、スレッドが何かを見つけたかどうかを確認するpthreadを起動することだと感じています。

これまで私がこれまで持っていたことは次のとおりです。何もプログラムにパイプされていない場合、期待どおりにスリープ状態になりますが、何かがstdinにある場合、スレッドは決して起動しません。

#include <iostream> 
#include <pthread.h> 
#include <stdlib.h> 

using namespace std; 

void *checkStdIn(void *d){ 
    char c = '\0'; 
    c = cin.peek(); 
    if (c){ 
     cout << c << endl; 
    } 
} 

int main(int argc, char *argv[]){ 

    pthread_t thread; 
    int rc; 
    rc = pthread_create(&thread, NULL, checkStdIn, NULL); 
    if (rc){ 
     cerr << "Error no. " << rc << endl; 
     exit(EXIT_FAILURE); 
    } 
    sleep(2); 

    return 0; 
}  
+0

プログラムはスレッドを実行する前に終了します。 –

+0

なぜそれを修復するのですか? –

+0

スレッドは入力を一度チェックし、何も見つからずに終了します。 –

答えて

4

pthreadsは必要ありません。select(2)またはpoll(2)を使用すると、アプリケーションをブロックせずに標準入力を覗くことができます。

/* According to POSIX.1-2001 */ 
#include <sys/select.h> 

/* According to earlier standards */ 
#include <sys/time.h> 
#include <sys/types.h> 
#include <unistd.h> 

#include <iostream> 

int 
my_peek(unsigned int nsecs) 
{ 
    struct timeval timeout; 
    fd_set rfds; 
    int fd; 

    // stdin file descriptor is 0 
    fd = 0; 

    timeout.tv_sec = nsecs; 
    timeout.tv_usec = 0; 

    FD_ZERO(&rfds); 
    FD_SET(fd, &rfds); 

    if (select(fd + 1, &rfds, NULL, NULL, &timeout) > 0) 
     return std::cin.peek(); 
    return -1; 
} 

int 
main(void) 
{ 
    int peek; 

    peek = my_peek(2); 
    if (peek != -1) { 
     std::cout << "we could peek without freezing" << std::endl; 
     std::cout << "my_peek() returned " << peek << std::endl; 
    } else { 
     std::cout << "we could not peek without freezing" << std::endl; 
    } 

    return 0; 
} 

ことに注意してください。そのために私はあなただけ(あなたが待ちたくない場合は、あなたも0を渡すことができます)あなたが入力待ちたい秒数を渡す必要がmy_peek()機能をコード化もしcinオブジェクトにデータがあるか、またはstdinFILE構造体にデータがあるかどうかを知るためには、select(2)に依存するのは悪いです.Nemoが述べたように、BUFFEREDです。この例では、read(2)を使用して「cin」を避けるのが最善の方法です。 http://linux.die.net/man/2/selectselect(2)マニュアルページをご覧ください詳細については

int 
my_peek(unsigned int nsecs) 
{ 
    struct timeval timeout; 
    fd_set rfds; 
    int fd; 
    unsigned char c; 

    // stdin file descriptor is 0 
    fd = 0; 

    timeout.tv_sec = nsecs; 
    timeout.tv_usec = 0; 

    FD_ZERO(&rfds); 
    FD_SET(fd, &rfds); 

    if (select(fd + 1, &rfds, NULL, NULL, &timeout) <= 0) 
     return -1; 
    if (read(fd, &c, 1) != 1) 
     return -1; 
    return static_cast<int>(c); /* or "return (int)c" for C-only programs */ 
} 

my_peek()の改良版は次のようになります。

PS:あなたはcpluplusサイトhttp://www.cplusplus.com/reference/iostream/streambuf/in_avail/で、あるいはistreamクラスのreadsome()方法で説明したようにstd::cin.rdbuf()->in_avail()で返される値に依存しようとすることができますが、彼らは通常で公開されていないFILEバッファに依存GNU C++ライブラリ。それをしないと、失敗するかもしれません。

+1

これは、POSIX対応プラットフォームを使用している場合、pthread対応環境にとっては最高の答えです。 OSがファイルディスクリプタ上の状態を伝えるだけでスレッドを生成する必要はありません。 (+1) –

+1

'std :: cin'は通常バッファされていないので、一般的にはうまくいきません。 (一度に1文字ずつループして読み込み、ファイルからstdinをリダイレクトしてみると、私の意図がわかります) – Nemo

+0

ありがとう、Nemo。私はこの例を修正し、バッファの問題を避けるためのヒントを追加しました。 –

0

それはあなたのスレッドが前にプログラムの終了に2マイクロ秒内に終了することを保証するものではありませんので、ごsleep(2)は無価値です。スレッドが終了するのを待つには、pthread_join(thread, NULL);を実装する必要があります。良い例はpthreadの例を参照してください。

また、cin.peek()は入力待機をブロックします。それがどのように設計されています。 cin.peekの例はこちらをご覧ください。

+0

'sleep '時間は実際には全秒ですが、とにかく参加する必要があります。 –

0

編集:フェルナンドによってninja'd Bawh、:)

わかりましたので、私は私はあなたが欲しいものを言うことができないので、最高の答えはあなたのためになるかについて100%わからないんだけどプログラムは最終的にです。です。

まず第一に、これはスレッドを使用して解決すべき問題ではありません。スレッドは、あらゆるものに対するキャッチオールソリューションではなく、一般に他のソリューションと比較して大きなオーバーヘッドを持っています。既にpthreadsを使用しているので、Windowsの互換性は問題ではないと考えます。

最初の手順では、標準モードを無効にして、enterを待つことなく文字を取得できるようにします。 stdinがターミナルではないことを100%確信した場合は、この手順をスキップできます。

#include <iostream> 
#include <termios.h> 

void toggle_canonical(bool on) { 
    struct termios terminal_settings; 

    // Get the existing terminal settings 
    tcgetattr(0 /* stdin */, &terminal_settings); 
    if(on) { 
     // Disable canonical mode 
     terminal_settings.c_lflag &= ~ICANON; 
     // Read at least one character. 
     terminal_settings.c_cc[VMIN] = 1; 
    } else { 
     // Enable canonical mode 
     terminal_settings.c_lflag |= ICANON; 
    } 
    tcsetattr(0 /* stdin */, TCSANOW, &terminal_settings); 

    return; 
} 

int main(const int argc, const char* argv[]) { 
    // The read timeout, which can be 0 if you don't want to block at all. 
    struct timeval to = {5 /* seconds */, 0 /* miliseconds */}; 
    fd_set read_fds; 
    int ret = 0; 

    // Turn canonical mode on 
    toggle_canonical(true); 

    FD_ZERO(&read_fds); 
    FD_SET(0, &read_fds); 

    // The first parameter to select() is the highest file 
    // descriptor in the set + 1, so in this case because 
    // STDIN == 0, we pass 1. This is actually completely 
    // ignored on several platforms, including Windows. 
    if((ret = select(1, &read_fds /* read set */, NULL /* write set */, NULL /* error set */, &to /* timeout */)) == 0) { 
     std::cout << "You didn't type anything in time." << std::endl; 
    } else if (ret == 1) { 
     std::cout << "Yay, you typed something in time!" << std::endl; 
    } else if (ret == -1) { 
     std::cout << "Oh no, an error occured!" << std::endl; 
    } 

    // Turn canonical mode off 
    toggle_canonical(false); 
    return 0; 
} 
関連する問題