非阻塞的stdio

4
我正在开发一个程序,该程序将从控制台接收用户输入,并在单独的线程中使用printf输出。我希望避免这样的情况:当用户正在输入某些内容时,printf输出会在光标处打印自己。
有没有一种方法可以在C语言中从控制台窗口进行非阻塞IO操作?理想情况下,捕获按键等操作,使用户输入的内容不会出现在屏幕上。我正在Ubuntu上开发,最好不要使用像ncurses这样的东西。
3个回答

5

使用termios,您可以禁用终端回显:

#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 */
}

在退出程序之前(使用atexit),您必须恢复终端:

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

谢谢。为什么要使用 ECHONL - Neil Traft

2
这是一个示例,展示如何从C中关闭回显。该示例直接来自一个HP论坛(我个人没有测试过)。

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.

否则,如果Bash是一个合适的方法,显然你可以只需执行stty -echo

0

如果我理解你的问题正确,关闭回显或使用非阻塞I/O并不是答案。相反,你想要防止后台线程中断用户输入线程,对吧?

为此,你需要访问原始按键而不是行缓冲输入。我不知道为什么你对ncurses或类似库过敏;那就是它们的用途!如果你喜欢,我猜你可以使用termios或ioctl调用来实现....

但是为了解决你的多线程TTY输出问题,你可以这样做:

1)创建一个互斥锁来控制谁可以访问控制台

在后台线程中,输出消息:

获取互斥锁;写入消息;释放互斥锁;然后进入睡眠状态!

在用户输入线程中:

当检测到新输入时,获取互斥锁。保持独占访问权限,直到用户按下回车键, 然后释放互斥锁并给后台线程机会进行通信。

这有帮助吗?


请查看cfmakeraw()以获取原始终端模式。在调用此函数之前,请确保保存termios结构,以便在完成后恢复它。 - Rob Jones

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接