Non-blocking stdio

喜你入骨 提交于 2019-12-18 07:04:38

问题


I'm working on a program which will be taking in user input from the console as well as printfing out in a separate thread. I want to avoid situations where the user is halfway through typing something in and a printf comes along and prints itself at the cursor.

Is there a way to do non-blocking io in c from the console window? Ideally, capturing keypresses or something like that such that what the user types doesn't appear on the screen. I'm developing in Ubuntu, and it's best if I don't have to use things like ncurses.


回答1:


using termios you can disable terminal echoing:

#include <termios.h>

struct termios oflags, nflags;
tcgetattr(fileno(stdin), &oflags);
nflags = oflags;
nflags.c_lflag &= ~ECHO;
nflags.c_lflag |= ECHONL;

if (tcsetattr(fileno(stdin), TCSANOW, &nflags) != 0) {
    /* handle error */
}

then before exit (use atexit) you must restore the terminal:

if (tcsetattr(fileno(stdin), TCSANOW, &oflags) != 0) {
    /* handle error */
}



回答2:


Here's an example of how to turn off echo from C, taken directly from an HP forum (and I haven't personally tested it):

Okay this should be a simple example of turning off echo:

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <termios.h>

#define STDIN_FDES 0

struct termios save;

int main(int argc, char *argv[])
{
int cc = 0;
char s_tmp[80],*p = NULL;
struct termios work;

cc = tcgetattr(STDIN_FDES,&save);
work = save;
work.c_lflag &= ~(ECHO);
cc = tcsetattr(STDIN_FDES,TCSANOW,&work);
(void) printf("\nEnter value: ");
(void) fflush(stdout);
p = fgets(s_tmp,sizeof(s_tmp),stdin);
if (p != NULL) (void) printf("Out -> %s\n",p);
cc = tcsetattr(STDIN_FDES,TCSANOW,&save);
return(cc);
}

NOTE: It is very important that you have signal handlers to catch SIGINT, SIGTERM, ... and reset the terminal using the original termios because the last tcsetattr() wins and this applies to the terminal device NOT simply the process. If you leave the process with echo off, it will be off in the shell as well.

Otherwise, if Bash is a suitable approach, apparently you can just do stty -echo.




回答3:


Turning off echo or using non-blocking I/O isn't the answer, if I understand your question correctly. Rather, you want to prevent a background thread from interrupting a user input thread, right?

For that, you'll need access to raw keypresses instead of line-buffered input. I don't know why you're allergic to ncurses or similar libraries; that's what they're for! I guess you could do it with termios or ioctl calls, if that's how you roll....

But to solve your multi-threaded TTY output problem, you could do this:

1) Create a mutex to control who can access the console

In the background thread, to output a message:

Grab the mutex; write the message; release the mutex; go back to sleep!

In the user input thread:

Grab the mutex when new input is detected. Keep exclusive access until the user hits enter, then release the mutex and give the background thread a chance to talk.

Does that help?



来源:https://stackoverflow.com/questions/1276029/non-blocking-stdio

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!