C - SIGALRM блокирует getchar()

Я работаю над многопроцессорным приложением терминала C. Приложение основано на меню, поэтому пользователь должен выбирать из возможностей для выполнения действия. Меню заблокировано функцией getchar(). Позвольте мне показать часть кода:

do
{
    do
    {
        printf("\n\n---------------\nMenu\n\n");
        printf("1. Option 1\n");
        printf("2. Option 2\n");
        printf("3. Option 3\n");
        printf("4. Exit");
        printf("\n\n---------------\n");

        scanf("%d", &end);

        int c = getchar();

        if(end < 1 || end > 4)
        {
            printf("Try it again!!!\n\n");
        }
    }
    while(end < 1 || end > 4);
}
while(end != 4);

Поэтому пользователю нужно выбрать один из вариантов. Но проблема в том, что второй вариант должен запускать функцию каждые 5 секунд в фоновом режиме. Один из дочерних элементов будет обрабатываться функцией. Итак, сначала я создал обработчик alarm() с помощью простого метода signal(). После этого я понял, что процесс ввода-вывода getchar() блокируется полученными сигналами. Я попытался создать новый дочерний элемент, который должен обрабатывать процессы стандартного ввода и отправлять результат в канал для родителя, но это тоже не сработало. Позвольте мне поделиться текущей частью обработки сигналов для лучшего понимания:

// Alarm handling
void CatchAlarm(int sig)
{
    if(someCounts > 0)
    {
        DoSomething();
        alarm(5);
    }
}

Также привязка будильника:

struct sigaction alarmAction;
alarmAction.sa_handler = CatchAlarm;
sigemptyset(&alarmAction.sa_mask);
alarmAction.sa_flags = SA_RESTART;
sigaction(SIGALRM, &alarmAction, NULL);

Моя проблема в том, что я не могу отправить родительский процесс в спящий режим, потому что пользователь должен иметь возможность выполнять другие действия во время ожидания тревоги. Когда я получаю SIGALRM, полный процесс чтения стандартного ввода сходит с ума. Пожалуйста, помогите мне, что я могу использовать, чтобы заблокировать чтение и ожидание взаимодействия с пользователем вместо getchar(), потому что я уже все перепробовал. Или, если кто-то может помочь мне, как я могу решить проблему, я могу это оценить. Конечно, если у вас есть дополнительные вопросы или проблемы, пожалуйста, дайте мне знать, и я обновлю свой вопрос как можно скорее. заранее спасибо


person MontyX    schedule 03.01.2015    source источник
comment
предполагая, что posix взглянет на select и poll,   -  person Jasen    schedule 04.01.2015
comment
@Jasen, можешь немного описать, почему ты это посоветовал? огромное спасибо   -  person MontyX    schedule 04.01.2015
comment
это способ эффективного ожидания входящих данных для нескольких файловых дескрипторов, таких как ваш канал и STDIN_FILENO. но не на ms-windows.   -  person Jasen    schedule 04.01.2015
comment
относительно запуска фонового процесса: предложите фоновому процессу поймать тревогу, запустить тревогу и т. д., а после того, как он сделает это, подождите/засните по тревоге. затем основной процесс запускает фоновый процесс только один раз. Основной процесс может запомнить идентификатор фонового процесса и послать ему сигнал уничтожения, когда основной процесс готов выйти.   -  person user3629249    schedule 04.01.2015
comment
@MontyX, man select и man poll Эти страницы руководства очень хорошо объясняют эти системные вызовы.   -  person Luis Colorado    schedule 07.01.2015
comment
Я не вижу никакого фонового процесса. В коде нет fork(2), поэтому только один процесс... но я не видел ни одного вызова alarm(3) в основном коде, так что если вы не просите ядро ​​прерывать вас, вас не прервут даже в первый раз.   -  person Luis Colorado    schedule 07.01.2015
comment
Мой код намного длиннее. Это только сомнительная часть. Есть двое раздвоенных детей. Был 3-й, когда я думал, что сигнал тревоги повлияет только на этот процесс, но я узнал, что sigalrm каким-то образом влияет на STDIN. Так влияют на всех детей и родителя тоже. Так что я не смог отделить эффект SIGALRM от getchar(). Конечно есть будильник(5); вызов до меню сделать-пока. Обработчик сигнала только перезапускает подсчет тревог каждый раз.   -  person MontyX    schedule 13.01.2015


Ответы (1)


Просто поместите вызов alarm(5); перед getchar();, чтобы ядру было рекомендовано отправить сигнал SIGALRM для прерывания getchar(3). Тогда вам не нужно помещать какой-либо код в обработчик сигнала (но вам нужен обработчик сигнала, иначе программа будет убита, см. alarm(2) и kill(2) для объяснения) Вам придется удалить его после вызова getchar в любом случае, иначе обработчик сигнала все равно будет вызван через 5 секунд, но это остается в качестве упражнения для читателя.

Примечание к обозначениям

В качестве стандарта в Unix в течение долгого времени ссылка наподобие getchar(3) означает справочную страницу для подпрограммы getchar, которая находится в разделе 3 интерактивного справочного руководства по Unix. Раздел 2 посвящен системным вызовам, а раздел 3 — библиотечным вызовам в прошлом.

person Community    schedule 07.01.2015
comment
Спасибо за Ваш ответ. Конечно, в моем коде первая отправка сигнала тревоги предшествует первому меню do-while, поэтому 1-й метод getchar(). Но это делает то же самое. У меня также есть обработчик сигнала, который запускает функцию DoSomething. - person MontyX; 13.01.2015