C GNU Readline(libreadline):异步显示输出消息
在使用readline(阻塞)进行用户输入时,我希望从另一个线程异步地将文本行输出到控制台。此外,我希望从控制台中删除readline提示符和当前部分输入行,写入输出行,然后恢复readline提示符和部分用户行,以便使输出看起来写在提示符的“上方” 通过读线再显示功能(或其他)的什么组合可以实现这一点 (重新显示函数文档:) 问题演示:C GNU Readline(libreadline):异步显示输出消息,c,linux,gnu,readline,libreadline,C,Linux,Gnu,Readline,Libreadline,在使用readline(阻塞)进行用户输入时,我希望从另一个线程异步地将文本行输出到控制台。此外,我希望从控制台中删除readline提示符和当前部分输入行,写入输出行,然后恢复readline提示符和部分用户行,以便使输出看起来写在提示符的“上方” 通过读线再显示功能(或其他)的什么组合可以实现这一点 (重新显示函数文档:) 问题演示: #include <readline/readline.h> #include <readline/history.h>
#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”)
所需输出:(缓慢输入“foo\nbar\n”)
我正在我的程序omphalos()的控制台版本中执行此操作。此特定代码来自 我有:
// 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);
}
及
每当有东西要打印时,它就会获取锁并调用clear_for_output(),将光标移动到当前行的开头。如果需要,它可以在此时通过调用rl_set_prompt()更改提示。完成后,它调用wake_input_thread(),释放锁并重新显示
我不确定这是否适用于您输入了超过一行文本的情况,并且对此表示怀疑,现在不想正式发现什么可能是新的令人沮丧的错误,所以您可以自己进行试验。我正在我的程序omphalos()的控制台版本中进行此操作。此特定代码来自 我有:
// 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);
}
及
每当有东西要打印时,它就会获取锁并调用clear_for_output(),将光标移动到当前行的开头。如果需要,它可以在此时通过调用rl_set_prompt()更改提示。完成后,它调用wake_input_thread(),释放锁并重新显示
我不确定这是否适用于您输入了超过一行文本并对此表示怀疑的情况,也不想正式发现此时可能出现的新的令人沮丧的错误,因此您可以自己进行试验。应该使用的功能:
。打印rl\u clear\u visible\u line()
不会很好,因为它只是将光标移动到行的开头,而没有删除行内容,而且当有多个输入行时,它无法正常工作\r
rl_on_new_line();rl_重新显示()代码>(或
):打印后rl_强制更新_显示();
似乎可以从任何线程调用这两个函数;但是,它可能会引入竞争条件(文档中没有说明从多个线程使用readline函数是否安全),因此最好使用
rl_event_hook
和rl_getc_function
(因为按住键时不会调用rl_event_hook
)来调用主线程的函数。还记得在没有运行的readline
函数时处理该函数。应该使用的函数:
。打印rl\u clear\u visible\u line()
不会很好,因为它只是将光标移动到行的开头,而没有删除行内容,而且当有多个输入行时,它无法正常工作\r
rl_on_new_line();rl_重新显示()代码>(或
):打印后rl_强制更新_显示();
似乎可以从任何线程调用这两个函数;但是,它可能会引入竞争条件(文档中没有说明从多个线程使用readline函数是否安全),因此最好使用
rl_event_hook
和rl_getc_function
(因为按住键时不会调用rl_event_hook
)来调用主线程的函数。还记得在没有运行readline
功能时处理says。您已经尝试了什么?;-)你已经试过什么了?;-)我已经确定,只要正确地交付SIGWINCH(即,到libreadline上下文中的线程),就不需要rl_redisplay()。我已经从我的代码中删除了它,一切都和以前一样好。assert(fputc('\r',fp)!=EOF)代码>在我看来像个bug。您不应该依赖于在assert()
中调用函数的副作用,因为显而易见的原因是,当编译assert时,函数调用也会……这种解决方案不仅在文本超过一行时是错误的,而且因为如果输入行长于打印行,它也不会清除该行(一个解决方法是打印\r\r
)感谢Alastair的更正(好眼睛!)--我编辑了我的回复。感谢@user202729提醒我编辑回复。我已经确定,如果一个正确地交付了SIGWINCH(即,到libreadline上下文中的线程),rl_redisplay()没有必要。我已经从代码中删除了它,并且一切都和以前一样正常。assert(fputc('\r',fp)!=EOF);
在我看来像个bug。你不应该依赖在assert()中调用的函数的副作用
原因很明显,当编译assert时,函数调用也会被调用……这种解决方案不仅在文本超过一行时是错误的,而且因为如果输入行比打印行长,它不会清除该行(解决方法是打印\r\r
),感谢Alastair的更正(眼睛好!)--我已经编辑了我的回复。感谢@user202729提醒我编辑回复。
// 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);
}