Получение пользовательского ввода без блокировки во время цикла с использованием потоков в C

#c #linux #pthreads #user-input

#c #linux #pthreads #пользовательский ввод

Вопрос:

Я хотел бы получить значение от пользователя, т.Е. заданное значение для переменной, внутри цикла while, не блокируя выполнение других задач. Я пытаюсь использовать pthreads, и моя пробная версия привела к сбою. Несмотря на то, что я использую pthread, программа блокируется scanf функцией.

Вот как я создаю pthread внутри функции main ()

 uint16_t refAngle = 0;
char refAngleString[64];

int main(void)
{
   pthread_t thread_id;

   while(1) {
       pthread_create(amp;thread_id, NULL, threadUserInput, NULL);
       pthread_join(thread_id, NULL);

       // Other functions were called below ...
   }
}
  

Затем у меня есть функция потока с именем threadUserInput

 void *threadUserInput(void* vargp)
{
    scanf("%s", refAngleString);
    refAngle = (uint16_t) atoi(refAngleString);
    printf("Angle is: %dn", refAngle);

    return NULL;
}
  

Любая помощь будет оценена, заранее спасибо.

Комментарии:

1. в этой функции: threadUserInput() отсутствует оператор: (void)vargp; и оператор: return NULL; должен быть: pthread_exit( NULL );

2. что касается: scanf("%s", refAngleString); Это не накладывает ограничений на длину слова, которое пользователю разрешено вводить, что может привести к переполнению входного буфера, что приводит к неопределенному поведению Для строки формата требуется модификатор MAX CHARACTERS, который на 1 меньше длины входного буфера, потому что ‘%s’ всегда добавляет NULбайт на ввод. Использование модификатора MAX CHARACTERS позволяет избежать любой возможности переполнения буфера и избежать любой возможности неопределенного поведения

3. что касается: ` while(1) { pthread_create(amp;thread_id, NULL, threadUserInput, NULL); pthread_join(thread_id, NULL); // Другие функции были вызваны ниже … }` это приводит к тому, что программа останавливается каждый раз на протяжении цикла. Предлагаю: pthread_create(amp;thread_id, NULL, threadUserInput, NULL); while(1) { // Other functions were called below ... } pthread_join(thread_id, NULL); Затем измените функцию потока на цикл, а не на текущий одиночный проход

4. Ваша последняя рекомендация сработала, спасибо!

5. Предложите использовать pthread_mutex so, чтобы условия гонки не приводили к тому, что поток вводил переменную, в то время как основная функция обрабатывает эту переменную

Ответ №1:

Несмотря на то, что я использую pthread, программа блокируется функцией scanf.

Ну, да. Созданный поток заблокирован scanf() , а родительский поток заблокирован в pthread_join() ожидании другого. У меня возникли проблемы с поиском какой-либо веской причины для запуска одного потока и последующего немедленного присоединения к нему, в отличие от простого прямого вызова функции потока.

Если вы хотите принимать пользовательский ввод один раз за итерацию цикла, но выполнять какую-то другую обработку (в рамках той же итерации), не дожидаясь этого ввода, то решение состоит в том, чтобы переместить pthread_join() вызов мимо всей работы, которая может быть выполнена до получения пользовательского ввода:

    while (1) {
       pthread_create(amp;thread_id, NULL, threadUserInput, NULL);

       // do work that does not require the user input ...

       pthread_join(thread_id, NULL);

       // do work that _does_ require the user input (if any) ...
   }
  

В качестве альтернативы, возможно, вы ищете что-то еще более развязанное, когда цикл выполняет столько итераций, сколько ему нравится, пока ввод не станет доступным. В этом случае вы должны запустить поток ввода-вывода вне цикла и просто продолжать его выполнение, считывая ввод за вводом. Пусть он предоставит какой-то сигнал, когда есть ввод, доступный для использования основным потоком. Схематически это может выглядеть так:

    pthread_create(amp;thread_id, NULL, threadAllUserInput, NULL);

   while (1) {

       // ... some work ...

       if (get_input_if_available(/* arguments */)) {
           // handle user input ...
       }

       // ... more work ...
   }

   force_input_thread_to_stop();
   pthread_join(thread_id, NULL);
  

Я опускаю все подробности о том, как get_input_if_available() и force_input_thread_to_stop() может быть реализовано. Существует несколько альтернатив, некоторые из которых будут лучше соответствовать вашим конкретным потребностям, чем другие.