Как программа C может опрашивать вводимые пользователем данные, одновременно выполняя другие действия в среде Linux? - PullRequest
13 голосов
/ 13 апреля 2019

Справочная информация:

Я относительно неопытный разработчик, пытающийся написать программное обеспечение для взаимодействия с контроллером движения PCI.Я использую C (скомпилированный с gcc) в Ubuntu Linux 18.04.

Программа, которую я пишу, должна регулярно проверять незапрошенные сообщения о состоянии, отправляемые контроллером движения (примерно раз в секунду), и отображать любыесообщения, которые он находит на экране терминала (для которого я использую библиотеку ncurses).

Что у меня есть:

Прямо сейчас, чтобы сделать это,Я вызываю функцию, которая проверяет наличие нежелательных сообщений в цикле while.Код примерно сродни:

while (1)
{
    // check for messages from PCI and store them in a traffic buffer
    checkForMessages(PCIconnection, trafficBuffer);

    // output the traffic buffer to the screen
    printf("%s", trafficBuffer);    
}

Что мне нужно:

Мне нужно, чтобы пользователю было предложено ввести данные таким образом, чтобы они могли завершитьпетля.Например, пользователь может ввести end, что приведет к остановке цикла и продолжению программы.

Проблема:

Я не знаю способачтобы достичь этого, не помещая fgets в цикл while, заставляя программу останавливаться и ждать, пока пользователь не введет что-то на каждой итерации цикла.

Я искал решение, но не нашелудалось найти обсуждение о том, как добиться функциональности, в которой я нуждаюсь.Открытие нового потока или процесса кажется шагом в правильном направлении?

Я открыт для полной реструктуризации своего кода, если то, что я сейчас делаю, является плохой практикой.

Спасибо залюбая помощь!

Ответы [ 3 ]

13 голосов
/ 13 апреля 2019

Ваша задача требует цикл обработки событий на основе select или epoll. Одним событием, которое он ожидает, является ввод данных пользователем - когда STDIN_FILENO становится готовым для чтения. Другим является периодический таймер на 1 секунду, когда вам нужно опросить контроллер.

Существует довольно много библиотек, которые реализуют цикл обработки событий для вас, чтобы вы могли сосредоточиться на том, какие события нужно обрабатывать и как. libevent - один из старейших, многофункциональных и популярных.

4 голосов
/ 13 апреля 2019

Я считаю, что «Unix» можно было бы не запрашивать ввод пользователя, а реагировать на сигнал пользователя.Например, когда пользователь нажимает Ctrl-C, текущий запущенный процесс получает SIGINT.

Пример того, как правильно использовать SIGINT для прерывания цикла, можно найти здесь .Копирование его в ответ, если ссылка устарела:

#include <stdlib.h>
#include <signal.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>

static volatile sig_atomic_t got_signal = 0;

static void my_sig_handler(int signo)
{
    got_signal = 1;
}

int main()
{
    struct sigaction sa;

    memset(&sa, 0, sizeof(struct sigaction));
    sa.sa_handler = &my_sig_handler;
    if (sigaction(SIGINT, &sa, NULL) == -1) {
        perror("sigaction");
        return EXIT_FAILURE;
    }

    for (;;) {
        if (got_signal) {
            got_signal = 0;
            printf("Received interrupt signal!\n");
        }
        printf("Doing useful stuff...\n");
        sleep(1); /* Sleep is not only useful, it is essential! */
    }
    return EXIT_SUCCESS;
}

(в вашем случае было бы неплохо поместить break; в блок if или использовать while(!got_signal))

3 голосов
/ 13 апреля 2019

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

char flag = 1;

while (flag) {
     // run the loop

     // if thing happens deploy the thread which will ask user for input

}

Я давно не занимался потоками, думаю, эта страница была бы лучше, чем я, пытаясь объяснить это вам: https://randu.org/tutorials/threads/

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...