принудительный выход из функции readline () - PullRequest
3 голосов
/ 26 февраля 2010

Я пишу программу на C ++, которая запускает GNU readline в отдельном потоке. Когда основной поток завершается, мне нужно завершить поток, в котором вызывается функция readline (). Функция readline () возвращается только тогда, когда поступил стандартный ввод (нажата клавиша ввода). Есть ли способ отправить ввод в приложение или явно вернуться из функции readline? Заранее спасибо.

Ответы [ 4 ]

2 голосов
/ 26 февраля 2010

Вместо возврата из основного потока вызовите exit (errno). Все остальные темы будут убиты мерзко!

Или, если вы хотите быть лучше, и, в зависимости от вашей ОС, вы можете отправить сигнал потоку readline, который прервет системный вызов.

Или, если вы хотите быть умнее, вы можете запустить readline в асинхронном режиме , используя цикл select () с таймаутом, чтобы ваш поток никогда не блокировался в функциях readine, а ваш поток мог очистить за собой.

2 голосов
/ 08 мая 2010

Я тоже экспериментировал с этой ситуацией. Я подумал, что, возможно, можно было бы вызвать 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 вызывающему потоку, чтобы вы могли выйти чисто вместо цикла для следующего ввода ( то же самое, что и если пользователь EOF'd ctrl-D)

Теперь вы можете съесть свой пирог (легко блокировать readlines) и съесть его тоже (иметь возможность остановиться на внешнем событии, не испортив терминал)

1 голос
/ 26 февраля 2010

C ++ стандартный ввод не предназначен для поточной защиты. Таким образом, даже если бы существовал метод, чтобы программно остановить его от ожидания ввода, вы не смогли бы вызвать его из другого потока. Конечно, для этого может существовать конкретный способ реализации.

0 голосов
/ 08 января 2016

Старый поток, но все еще API readline, похоже, не исследован.

Чтобы сначала прервать 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.

...