GNU readline を別のスレッドで実行するプログラムを c++ で作成しています。メインスレッドが終了したら、 readline() 関数が呼び出されたスレッドを終了する必要があります。readline() 関数は、標準入力が来た (Enter が押された) 場合にのみ返されます。入力をアプリケーションに送信したり、readline 関数から明示的に返す方法はありますか? 前もって感謝します。
4 に答える
メインスレッドから戻る代わりに、exit(errno) を呼び出します。他のすべてのスレッドは厄介に殺されます!
または、OS によっては、システムコールを中断するシグナルを readline スレッドに送信することもできます。
または、より賢くしたい場合は、readline を非同期モードで実行し、 select() ループをタイムアウト付きで使用して、スレッドが readine 関数でブロックされないようにし、スレッド自体をクリーンアップできるようにすることができます。
私もこの状況で実験しました。おそらく close(STDIN_FILENO) を呼び出すことができると思いましたが、これにより readline が他のスレッドに返されますが、何らかの理由で端末が悪い状態のままになります(文字がエコーされないため、自分が何をしているのかわかりません)タイピング)。ただし、「リセット」コマンドを呼び出すとこれが修正されるため、完全な代替手段は次のとおりです。
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 を中断すると、readline に -1 が返され、呼び出しスレッドに 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 を使用してそれらのファイルを読み込む対話型デバッグの目的で使用しました。