42

C で Linux/OS X のノンブロッキング コンソール IO を行うにはどうすればよいですか?

4

7 に答える 7

27

例を追加したい:

#include <unistd.h>
#include <fcntl.h>
#include <stdio.h>

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

{
    char buf[20];
    fcntl(0, F_SETFL, fcntl(0, F_GETFL) | O_NONBLOCK);
    sleep(4);
    int numRead = read(0, buf, 4);
    if (numRead > 0) {
        printf("You said: %s", buf);
    }
}

このプログラムを実行すると、標準入力に入力を提供するのに 4 秒かかります。入力が見つからない場合、ブロックせずに単に戻ります。

2 つの実行例:

Korays-MacBook-Pro:~ koraytugay$ ./a.out
fda 
You said: fda
Korays-MacBook-Pro:~ koraytugay$ ./a.out
Korays-MacBook-Pro:~ koraytugay$ 
于 2015-05-30T16:42:11.100 に答える
23

Pete Kirkhamのように、私はcc.byexamples.comを見つけました。問題の適切な説明と ncurses のバージョンについては、そこにアクセスしてください。

私のコードでは、標準入力またはファイルから初期コマンドを取得し、初期コマンドの処理中にキャンセル コマンドを監視する必要がありました。scanf()私のコードはC++ですが、C++入力関数を使用する残りの部分を使用できるはずですgetline()

肉は、利用可能な入力があるかどうかを確認する関数です。

#include <unistd.h>
#include <stdio.h>
#include <sys/select.h>

// cc.byexamples.com calls this int kbhit(), to mirror the Windows console
//  function of the same name.  Otherwise, the code is the same.
bool inputAvailable()  
{
  struct timeval tv;
  fd_set fds;
  tv.tv_sec = 0;
  tv.tv_usec = 0;
  FD_ZERO(&fds);
  FD_SET(STDIN_FILENO, &fds);
  select(STDIN_FILENO+1, &fds, NULL, NULL, &tv);
  return (FD_ISSET(0, &fds));
}

これは、標準入力入力関数の前に呼び出す必要がありますstd::cin。この関数を使用する前に使用すると、再び true が返されることはありませんでした。たとえば、main()次のようなループがあります。

int main(int argc, char* argv[])
{ 
   std::string initialCommand;
   if (argc > 1) {
      // Code to get the initial command from a file
   } else {
     while (!inputAvailable()) {
       std::cout << "Waiting for input (Ctrl-C to cancel)..." << std::endl;
       sleep(1);
     }
     std::getline(std::cin, initialCommand);
   }

   // Start a thread class instance 'jobThread' to run the command
   // Start a thread class instance 'inputThread' to look for further commands
   return 0;
}

入力スレッドでは、新しいコマンドがキューに追加され、 によって定期的に処理されましたjobThread。は、次のinputThreadように少し見えました。

THREAD_RETURN inputThread()
{
  while( !cancelled() ) {
    if (inputAvailable()) {
      std::string nextCommand;
      getline(std::cin, nextCommand);
      commandQueue.lock();
      commandQueue.add(nextCommand);
      commandQueue.unlock();
    } else {
        sleep(1);
    }
  }
  return 0;
}

この関数はおそらくmain().

私のシステムでは、改行が送信されるまで利用可能な入力はありませんでした。これはまさに私が望んでいたことでした。入力時にすべての文字を読みたい場合は、stdin で「正規モード」をオフにする必要があります。 cc.byexamples.comには、私が試したことのないいくつかの提案がありますが、残りはうまくいったので、うまくいくはずです。

于 2009-08-14T23:26:43.197 に答える
7

あなたは本当にそうしません。TTY (コンソール) はかなり制限されたデバイスであり、ノンブロッキング I/O はほとんど行いません。curses/ncurses アプリケーションなどで、非ブロッキング I/O のように見えるものを見たときに行うことは、raw I/Oと呼ばれます。raw I/O では、文字の解釈や消去処理などはありません。代わりに、他のことをしながらデータをチェックする独自のコードを記述する必要があります。

最新の C プログラムでは、コンソール I/O をスレッドまたは軽量プロセスに配置することで、これを別の方法で単純化できます。その後、I/O は通常のブロッキング方式で続行できますが、データをキューに挿入して別のスレッドで処理することができます。

アップデート

これは、それをさらにカバーするcursesチュートリアルです。

于 2009-04-04T18:47:41.933 に答える
7

I bookmarked "Non-blocking user input in loop without ncurses" earlier this month when I thought I might need non-blocking, non-buffered console input, but I didn't, so can't vouch for whether it works or not. For my use, I didn't care that it didn't get input until the user hit enter, so just used aio to read stdin.

于 2009-04-04T18:59:55.990 に答える
4

C++ を使用した関連する質問を次に示します --クロスプラットフォーム (linux/Win32) ノンブロッキング C++ IO on stdin/stdout/stderr

于 2009-04-04T18:40:38.157 に答える
4

ncurses またはスレッドを使用する別の方法は、GNU Readlineを使用することです。特に、コールバック関数を登録できる部分です。パターンは次のとおりです。

  1. STDIN で select() を使用します (他の記述子の中でも)
  2. select() が STDIN から読み取る準備ができていることを通知したら、readline の rl_callback_read_char() を呼び出します。
  3. ユーザーが完全な行を入力すると、rl_callback_read_char がコールバックを呼び出します。それ以外の場合は、すぐに戻り、他のコードを続行できます。
于 2009-08-14T23:37:17.700 に答える
0

「コンソール IO」の意味がよくわかりません -- STDIN から読み取っていますか、それとも他のソースから読み取るコンソール アプリケーションですか?

STDIN から読み取る場合は、fread() をスキップして read() と write() を poll() または select() と一緒に使用して、呼び出しがブロックされないようにする必要があります。setbuf() を使用すると、fread が EOF を返す原因となる入力バッファリングを無効にできるかもしれませんが、試したことはありません。

于 2009-04-04T18:45:12.110 に答える