Как прекратить ожидание на входе пользователя? - PullRequest
3 голосов
/ 07 июля 2019

Я работаю над файловым менеджером на основе ncurses в C. Проблема в том, что некоторым дочерним процессам может потребоваться некоторое время для завершения, и пока это не произойдет, он останется зависшим из-за waitpid.

Я не могу использовать флаг WNOHANG, потому что следующий блок кода зависит от вывода дочернего процесса.

void getArchivePreview(char *filepath, int maxy, int maxx)
{
    pid_t pid;
    int fd;
    int null_fd;

    // Reallocate `temp_dir` and store path to preview file
    char *preview_path = NULL;
    allocSize = snprintf(NULL, 0, "%s/preview", cache_path);
    preview_path = malloc(allocSize+1);
    if(preview_path == NULL)
    {
        endwin();
        printf("%s\n", "Couldn't allocate memory!");
        exit(1);
    }
    snprintf(preview_path, allocSize+1, "%s/preview", cache_path);

    // Create a child process to run "atool -lq filepath > ~/.cache/cfiles/preview"
    pid = fork();
    if( pid == 0 )
    {
        remove(preview_path);
        fd = open(preview_path, O_CREAT | O_WRONLY, 0755);
        null_fd = open("/dev/null", O_WRONLY);
        // Redirect stdout
        dup2(fd, 1);
        // Redirect errors to /dev/null
        dup2(null_fd, 2);
        execlp("atool", "atool", "-lq", filepath, (char *)0);
        exit(1);
    }
    else
    {
        int status;
        waitpid(pid, &status, 0);
        getTextPreview(preview_path, maxy, maxx);
        free(preview_path);
    }
}

В этом случае я хотел бы продолжить работу с остальной частью программы, если пользователь решит перейти к какому-либо другому файлу. Каким образом я могу изменить архитектуру программы?

1 Ответ

2 голосов
/ 07 июля 2019

Если я правильно понял вопрос, то вы хотите разблокировать родительский элемент либо при завершении дочернего, либо при любом вводе пользователем.

Как указано в этом комментарии, вы можете обработать SIGCHLDи еще один сигнал сказать SIGUSR1.SIGUSR1 будет повышено, когда вы получите пользовательский ввод.Ниже приведен пример, где обрабатываются и SIGCHLD, и 'SIGUSR1'.Если использовать входные данные для любого числа, тогда оно поднимает SIGUSR1 до родительского и родительского kill дочернего.Еще ребенок поднимет SIGCHLD на выходе.

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

int raised_signal = -1; 

static void cb_sig(int signal)
{
        if (signal == SIGUSR1)
                raised_signal = SIGUSR1;
        else if (signal == SIGCHLD)
                raised_signal = SIGCHLD;
}

int main()
{
        int pid;
        int i, a;
        struct sigaction act;

        sigemptyset(&act.sa_mask);
        act.sa_flags = 0;
        act.sa_handler = cb_sig;

        if (sigaction(SIGUSR1, &act, NULL) == -1) 
                printf("unable to handle siguser1\n");
        if (sigaction(SIGCHLD, &act, NULL) == -1) 
                printf("unable to handle sigchild\n");

        pid = fork();
        if (pid == 0) {
                /* child */
                for (i = 0; i < 10; i++) {
                        sleep(1);
                        printf("child is working\n");
                }
                exit(1);
        } else {
                /* parent */
                if (-1 ==  scanf("%d", &a)) {
                        if (errno == EINTR)
                                printf("scanf interrupted by signal\n");
                } else {
                        raise(SIGUSR1);
                }

                if (raised_signal == SIGUSR1) {
                        printf("user terminated\n");
                        kill(pid, SIGINT);
                } else if (raised_signal == SIGCHLD) {
                        printf("child done working\n");
                }

                exit(1);
        }

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