Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do you do non-blocking console I/O on Linux in C?

How do you do nonblocking console IO on Linux/OS X in C?

like image 818
nonpolynomial237 Avatar asked Apr 04 '09 18:04

nonpolynomial237


People also ask

What is non-blocking IO in C?

Sometimes it's convenient to have I/O that doesn't block i.e we don't want a read call to block on one in case of input from the other. Solution for this is the given function: To specify non-blocking option: #include<fcntl. h> int fd; fcntl(fd, F_SETFL, O_NONBLOCK);

What is non-blocking IO in Linux?

For network socket i/o, when it is "ready", it don't block. That's what the O_NONBLOCK and "ready" means. For disk i/o, we have posix aio, linux aio, sendfile and friends. Follow this answer to receive notifications.

Is Linux write blocking?

Succinctly, both read() and write() can be blocking or non-blocking, depending on circumstances.

Is read blocking?

By default, read() waits until at least one byte is available to return to the application; this default is called “blocking” mode. Alternatively, individual file descriptors can be switched to “non-blocking” mode, which means that a read() on a slow file will return immediately, even if no bytes are available.


2 Answers

I want to add an example:

#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);     } } 

When you run this program you have 4 seconds to provide input to standard in. If no input found, it will not block and will simply return.

2 sample executions:

Korays-MacBook-Pro:~ koraytugay$ ./a.out fda  You said: fda Korays-MacBook-Pro:~ koraytugay$ ./a.out Korays-MacBook-Pro:~ koraytugay$  
like image 114
Koray Tugay Avatar answered Sep 18 '22 14:09

Koray Tugay


Like Pete Kirkham, I found cc.byexamples.com, and it worked for me. Go there for a good explanation of the problem, as well as the ncurses version.

My code needed to take an initial command from standard input or a file, then watch for a cancel command while the initial command was processed. My code is C++, but you should be able to use scanf() and the rest where I use the C++ input function getline().

The meat is a function that checks if there is any input available:

#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)); } 

This has to be called before any stdin input function When I used std::cin before using this function, it never returned true again. For example, main() has a loop that looks like this:

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; } 

In the input thread, new commands were added to a queue, which was periodically processed by the jobThread. The inputThread looked a little like this:

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; } 

This function probably could have been in main(), but I'm working with an existing codebase, not against it.

For my system, there was no input available until a newline was sent, which was just what I wanted. If you want to read every character when typed, you need to turn off "canonical mode" on stdin. cc.byexamples.com has some suggestions which I haven't tried, but the rest worked, so it should work.

like image 31
6 revs, 5 users 94% Avatar answered Sep 20 '22 14:09

6 revs, 5 users 94%