我正在用 c++ 编写程序,它在单独的线程中运行 GNU readline。当主线程退出时,我需要完成调用 readline() 函数的线程。readline() 函数仅在标准输入出现(按下输入)时返回。有没有办法将输入发送到应用程序或从 readline 函数显式返回?提前致谢。
4 回答
不是从主线程返回,而是调用 exit(errno)。所有其他线程将被严重杀死!
或者,如果您想变得更好,并且根据您的操作系统,您可以向 readline 线程发送一个信号,这将中断系统调用。
或者,如果您想更聪明一点,您可以在异步模式下运行 readline,使用带有超时的 select() 循环,这样您的线程就不会在 readine 函数中阻塞,并且您的线程可以自行清理。
我也尝试过这种情况。我想也许有人可以调用 close(STDIN_FILENO),这确实会导致 readline 在另一个线程上返回,但由于某种原因,它会使终端处于错误状态(不回显字符,所以你看不到你是什么打字)。但是,调用“reset”命令将解决此问题,因此完整的替代方法是:
close(STDIN_FILENO);
pthread_join(...); // or whatever to wait for thread exit
system("reset -Q"); // -Q to avoid displaying cruft
但是,受其他建议的启发,我使用的最终更好的解决方案是覆盖 rl_getc:
rl_getc_function = getc; // stdio's getc passes
然后你可以使用 pthread_kill() 发送一个信号来中断 getc,它返回一个 -1 到 readline,它返回一个 NULL 给调用线程,这样你就可以干净地退出而不是循环下一个输入(与将如果用户通过 ctrl-D 进行 EOF,则会发生)
现在你可以吃你的蛋糕(容易阻塞 readlines)并吃它(能够通过外部事件停止而不会搞砸终端)
C++ 标准输入并非设计为线程安全的。因此,即使有一种方法可以以编程方式阻止它等待输入,您也无法从另一个线程调用它。当然,可以有一种特定于实现的方式来做到这一点。
旧线程但仍然 readline API 似乎没有探索。
为了首先中断 readline,我禁用了 readline 信号处理程序。不要看我正在使用的丑陋的 global_buffer - 这只是一个例子
http://www.delorie.com/gnu/docs/readline/rlman_43.html
读者话题:
pthread_mutex_t lock;
int isBufferReady = 0;
char global_buffer[2500]; /// Assuming that reads will not be any bigger
void *reader_thread(void *arg)
{
rl_getc_function = getc;
rl_catch_signals = 0;
rl_catch_sigwinch = 0;
char *input;
while ( (input = readline( NULL )) )
{
i = strlen(input)-1;
if ( input[i] == '\0' )
return NULL;
/// Due to TAB there might be a whitespace in the end
while ( i > 0 )
{
if ( isspace(input[i]) )
{
input[i] = '\0';
}
else
{
break;
}
i--;
}
pthread_mutex_lock(&lock);
read_file_function( input, buffer );
free(input);
isBufferReady = 1;
pthread_mutex_unlock(&lock);
}
printf( "Im closed \n" );
return NULL;
}
信号处理程序:
volatile int keepRunning = 1;
void SIG_handler(int signal)
{
int static sig_count = 0;
switch ( signal )
{
case SIGUSR2:
{
/// Yeah I know I should not printf in a signal handler
printf( "USR2: %d \n", sig_count++);
break;
}
default:
{
printf( " SIGHANDLE\n" );
keepRunning = 0;
break;
}
}
}
主要的:
int main( int argc, char *argv[] )
{
pthread_t file_reader;
{ /// Signal Handler registration
struct sigaction sigact = {{0}};
sigact.sa_handler = SIG_handler;
// sigact.sa_flags = SA_RESTART;
sigaction(SIGINT , &sigact, NULL);
sigaction(SIGQUIT, &sigact, NULL);
sigaction(SIGTERM, &sigact, NULL);
sigaction(SIGHUP, &sigact, NULL);
// sigaction(SIGUSR1, &sigact, NULL);
sigaction(SIGUSR2, &sigact, NULL);
}
pthread_create( &file_reader, NULL, reader_thread, NULL );
while(keepRunning)
{
pthread_mutex_lock(&lock);
if( !isBufferReady )
{
... fill in global_buffer according to some algorithm
}
pthread_mutex_unlock(&lock);
usleep(10);
pthread_mutex_lock(&lock);
if(isBufferReady)
isBufferReady = 0;
... some operation on the 'global_buffer' like write its contents to socket
pthread_mutex_unlock(&lock);
usleep(10);
}
signal(SIGINT, SIG_DFL);
pthread_cancel( file_reader );
pthread_join( file_reader, NULL);
pthread_mutex_destroy(&lock);
rl_cleanup_after_signal();
return 0;
}
有了这个(远非完美)代码片段,我终于能够在没有描述之前描述的片状的情况下中断 readline。
将此代码片段用于交互式调试目的,我在简单的文本文件中准备了数据包,并在 readline 的帮助下读入了这些文件。