【问题标题】:Non-blocking stdio非阻塞标准输出
【发布时间】:2010-11-19 13:09:16
【问题描述】:

我正在开发一个程序,该程序将从控制台接收用户输入并在单独的线程中打印出来。我想避免用户在输入内容到一半时出现 printf 并在光标处打印自己的情况。

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

【问题讨论】:

    标签: c multithreading unix nonblocking


    【解决方案1】:

    下面是一个如何从 C 中关闭 echo 的示例,直接取自 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,因为 最后 tcsetattr() 获胜,这适用 到终端设备不仅仅是 过程。如果你离开这个过程 echo off,它将在 shell 中关闭 也是。

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

    【讨论】:

      【解决方案2】:

      使用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
      【解决方案3】:

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

      为此,您需要访问原始按键而不是行缓冲输入。我不知道你为什么对 ncurses 或类似的库过敏;这就是他们的目的!我想你可以通过 termios 或 ioctl 调用来做到这一点,如果你这样做的话......

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

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

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

      获取互斥锁;写信息;释放互斥锁;回去睡觉吧!

      在用户输入线程中:

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

      这有帮助吗?

      【讨论】:

      • 查看原始终端模式的 cfmakeraw()。请务必在调用此函数之前保存 termios 结构,以便在完成后恢复它。
      猜你喜欢
      • 1970-01-01
      • 2011-12-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-03-29
      • 1970-01-01
      相关资源
      最近更新 更多