非阻塞stdio

时间:2009-08-14 04:24:25

标签: c multithreading unix nonblocking

我正在开发一个程序,它将从控制台接收用户输入以及在单独的线程中打印出来。我希望避免用户在输入内容的中途并且printf出现并在光标处打印自己的情况。

有没有办法在控制台窗口中执行c中的非阻塞io?理想情况下,捕获按键或类似的东西,使得用户键入的内容不会出现在屏幕上。我正在开发Ubuntu,如果我不必使用像ncurses这样的东西,那就最好了。

3 个答案:

答案 0 :(得分:4)

使用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 */
}

答案 1 :(得分:2)

以下是一个如何关闭来自C的回声的示例,直接来自an HP forum(我还没有亲自测试过):

  

好的,这应该是一个简单的例子   关闭回声:

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

注意:您非常重要   有信号处理程序来捕获SIGINT,   SIGTERM,...并重置终端   使用原始termios因为   last tcsetattr()获胜,这适用   终端设备不仅仅是   处理。如果你离开这个过程   回声,它将在shell中关闭   同样。

否则,如果Bash是一种合适的方法,显然你可以做stty -echo

答案 2 :(得分:0)

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

为此,您需要访问原始按键而不是行缓冲输入。我不知道你为什么对ncurses或类似的图书馆过敏;这就是他们的目的!我想你可以用termios或ioctl调用来做,如果这就是你滚动的方式......

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

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

在后台线程中输出消息:

抓住互斥锁;写信息;释放互斥锁;回去睡觉!

在用户输入主题中:

检测到新输入时抓取互斥锁。在用户点击进入之前保持独占访问权限, 然后释放互斥锁,让后台线程有机会说话。

这有帮助吗?