【问题标题】:GNU Readline (libreadline): Displaying output message asynchronouslyGNU Readline (libreadline):异步显示输出消息
【发布时间】:2012-03-07 05:49:35
【问题描述】:

在使用 readline(阻塞)进行用户输入时,我想从另一个线程异步地将文本行输出到控制台。此外,我希望从控制台中删除 readline 提示和当前部分输入行,写入输出行,然后恢复 readline 提示和部分用户行 - 以使输出看起来写在“上面”提示。

通过 readline redisplay 功能(或其他方式)的哪种组合可以实现这一点?

(重新显示函数文档:http://cnswww.cns.cwru.edu/php/chet/readline/readline.html#SEC35

问题演示

    #include <readline/readline.h>
    #include <readline/history.h>
    #include <unistd.h>
    #include <stdlib.h>
    #include <pthread.h>

    bool run = true;

    void* log_thread(void*)
    {
            while (run)
            {
                    sleep(1);
                    // WHAT TO DO HERE?
                    write(1, "tick\n", 5);
            }
    }

    int main()
    {
            pthread_t t;
            pthread_create(&t, 0, log_thread, 0);

            while (true)
            {
                    char* p = readline("? ");
                    free(p);

                    if (!p)
                            break;
            }

            run = false;
            pthread_join(t,0);
    }

构建

$ g++ -pthread -lreadline test.cpp
$ ./a.out

观察到的输出:(输入“foo\nbar\n”输入缓慢)

? tick
ftick
otick
otick

? tick
tick
bartick
tick

? tick
^C

期望的输出:(输入“foo\nbar\n”输入缓慢)

tick
tick
tick
tick
tick
? foo

tick
tick
tick
tick
tick
? bar

tick
? ^C

【问题讨论】:

  • 你已经尝试了什么? ;-)

标签: c linux gnu readline libreadline


【解决方案1】:

我在我的程序 omphalos (https://github.com/dankamongmen/omphalos) 的控制台版本中执行此操作。此特定代码来自https://github.com/dankamongmen/omphalos/blob/master/src/ui/tty/tty.c

我有:

// Call whenever we generate output, so that the prompt is updated
static inline void
wake_input_thread(void){
    if(input_tid){
            pthread_kill(*input_tid,SIGWINCH);
            rl_redisplay(); // FIXME probably need call from readline contex
    }
    pthread_mutex_unlock(&promptlock);

}

static inline void
clear_for_output(FILE *fp){
    fputc('\r',fp);
}

只要有东西要打印,它就会获取锁并调用 clear_for_output(),将光标移动到当前行的开头。如有必要,此时可以通过调用 rl_set_prompt() 来更改提示。完成后,它调用wake_input_thread(),释放锁并重新显示。

我不确定这是否适用于您输入的文本超过一行的情况,并且对此表示怀疑,并且不关心此时正式发现可能是一个新的令人沮丧的错误,所以你可以自己试验一下。

【讨论】:

  • 我已经确定,只要正确地传递 SIGWINCH(即,传递到 libreadline 上下文中的线程),就不需要 rl_redisplay()。我已将其从我的代码中删除,并且一切正常。
  • assert(fputc('\r',fp) != EOF); 对我来说似乎是一个错误。您不应该依赖在assert() 中调用的函数的副作用,原因很明显,当编译出断言时,函数调用也将......
  • 这个解决方案是错误的,不仅在文本多于一行的情况下,而且如果输入行比打印行长,它不会清除该行(解决方法是打印@987654327 @)
  • 感谢 Alastair 的更正(好眼光!)——我已经编辑了我的回复。感谢@user202729 提醒我编辑回复。
【解决方案2】:

应该使用的函数:

  • rl_clear_visible_line()。打印\r就不行了,因为它只是将光标移动到行首而不删除行内容,而且当输入多行时无法正常工作。
  • rl_on_new_line(); rl_redisplay();(或rl_forced_update_display();):打印后。

似乎可以从任何线程调用这两个函数;但是它可能会引入竞争条件(文档没有说明从多个线程使用 readline 函数是否安全),因此最好使用 rl_event_hookrl_getc_function (因为在按住键时不会调用 rl_event_hook)调用主线程的函数。还记得在没有运行readline 函数时处理says。

【讨论】:

    猜你喜欢
    • 2019-05-22
    • 1970-01-01
    • 1970-01-01
    • 2013-09-20
    • 2019-08-16
    • 2016-11-06
    • 1970-01-01
    • 2022-08-13
    • 2023-02-26
    相关资源
    最近更新 更多