1

在使用 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
4

2 回答 2

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(),释放锁并重新显示。

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

于 2012-06-11T00:08:23.877 回答
0

应该使用的功能:

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

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

于 2019-10-02T16:37:10.347 回答