【问题标题】:how to output messages to stdout on another thread while reading from stdin with GNU readline without messing up the inputs?如何在使用 GNU readline 从标准输入读取时将消息输出到另一个线程上的标准输出而不会弄乱输入?
【发布时间】:2011-07-01 10:18:42
【问题描述】:

抱歉,标题太长了。我正在用 C 语言开发一个网络程序,它可以在标准输出上显示从网络接收到的消息,并通过 GNU readline 库在标准输入上接受用户输入。 问题是,当用户通过 readline 在主线程上输入命令时,网络消息到达并输出到 stdout,这将产生如下内容:

场景:

输入:1234567890
网络消息:你好
当用户刚刚输入“7”时,网络消息到达

终端实际输出:

输入> 1234567Hello
890_

有没有办法得到这样的输出?

你好
输入>1234567890_

附言_ 是光标。

提前致谢!

【问题讨论】:

  • 我认为由于 readline 的设计,您想要实现的目标相当困难。您可以尝试一些技巧,将光标移动转义符附加到您的消息中并将其全部发送到单个write,但仍然可能存在竞争条件,并且很难处理已换行的输入行。

标签: c pthreads readline libreadline


【解决方案1】:

好的,我在四处搜索后找到了解决方案,并对 printf() 进行了以下替换。通过使用 rl_replace_line("", 0) 它将清除当前行并将光标放在行首,然后我可以打印一行消息,然后恢复 readline 提示,将原始行替换回原处,然后恢复光标位置。
但是,这个 hack 需要在调用这个 printf 函数时在末尾包含一个 \n,否则该行将被 readline 覆盖。

#define printf(...) my_rl_printf(__VA_ARGS__)
void my_rl_printf(char *fmt, ...)
{
    int need_hack = (rl_readline_state & RL_STATE_READCMD) > 0;
    char *saved_line;
    int saved_point;
    if (need_hack)
    {
        saved_point = rl_point;
        saved_line = rl_copy_text(0, rl_end);
        rl_save_prompt();
        rl_replace_line("", 0);
        rl_redisplay();
    }

    va_list args;
    va_start(args, fmt);
    vprintf(fmt, args);
    va_end(args);

    if (need_hack)
    {
        rl_restore_prompt();
        rl_replace_line(saved_line, 0);
        rl_point = saved_point;
        rl_redisplay();
        free(saved_line);
    }
}

【讨论】:

    【解决方案2】:

    转储readline 并读取用户输入的每个char。如果在用户输入时收到任何网络消息,请清除当前行,输出网络消息,然后重新打印用户当前输入的行。

    这似乎需要做很多工作,但这是我现在想到的唯一方法。

    如果您确实转储readline,那么您可以使用curses,这样会更容易...

    【讨论】:

      【解决方案3】:

      这可以使用curses(3) 库来完成。

      【讨论】:

      • 不幸的是,来自this post,curses 和 readline 不能混合使用。
      【解决方案4】:

      您应该在这两个线程之间进行某种同步。一个互斥锁或者只是一个从一个线程到另一个线程的标志,表明它正在使用标准输入或标准输出。

      【讨论】:

      • 在这种情况下,我必须等待用户完成输入行以显示传入消息。但是,消息应在到达后立即显示。
      • 哦,那我猜RedX的方法就是答案了。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-07-22
      • 2012-09-25
      • 2015-01-31
      • 1970-01-01
      • 2012-04-25
      • 2011-01-08
      • 1970-01-01
      相关资源
      最近更新 更多