Не вызывается обработчик при отправке сигнала killpg

Не вызывается обработчик при отправке сигнала killpg

23.04.2019 11:00:40 Просмотров 37 Источник

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

Для примера привожу код для двух дочерних процессов:

int procNum;
pid = fork();
if(pid==0)
{
    procNum = 1;
    signal(SIGUSR1, getSignal);
    setpgrp();
    createFile(procNum);// Создает файл с pid процесса
    pid = fork();
    if(pid==0)
    {
        procNum = 2;
        createFile(procNum);
    }
}

В родительском процессе проверяю, существуют ли нужные мне файлы и вызываю

while(!checkTree());
killpg(readPid(1), SIGUSR1);
//readPid считывает pid нужного процесса из файла

Функция checkTree:

int checkTree()
{
    char path[30];
    FILE *f;
    for (int i = 1; i <= 8; i++)
    {
        snprintf(path, sizeof(path), "/tmp/Lab4_%d.txt",i);
        if((f = fopen(path, "r")) == NULL)              
            return 0;
        else 
        {
            fscanf (f, "%d", &pid);
            if(pid > 0)
                continue;
        }
    }
    return 1;
}

Код обработчика:

void getSignal(int sig)
{
    printf("%d %d %d получил %d\n", procNum, getpid(), getppid(), sig);
}

При запуске программы с различной периодичностью получаю результаты:

1 5187 5185 получил 30

Либо

1 5205 5203 получил 30
2 5206 5205 получил 30

Почему иногда не срабатывает второй обработчик?

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

Если мое предположение верно, то каким образом можно этого избежать?

Если нет, то подскажите, пожалуйста, в чем проблема.

У вопроса есть решение - Посмотреть?

https://ru.stackoverflow.com/questions/972905/%d0%9d%d0%b5-%d0%b2%d1%8b%d0%b7%d1%8b%d0%b2%d0%b0%d0%b5%d1%82%d1%81%d1%8f-%d0%be%d0%b1%d1%80%d0%b0%d0%b1%d0%be%d1%82%d1%87%d0%b8%d0%ba-%d0%bf%d1%80%d0%b8-%d0%be%d1%82%d0%bf%d1%80%d0%b0%d0%b2%d0%ba%d0%b5-%d1%81%d0%b8%d0%b3%d0%bd%d0%b0%d0%bb%d0%b0-killpg#comment1633517_972905
приведенного кода не достаточно. может у вас файл еще не успевает создаться. И кстати, зачем файлы, если родитель и так получает pid порожденного процесса
https://ru.stackoverflow.com/questions/972905/%d0%9d%d0%b5-%d0%b2%d1%8b%d0%b7%d1%8b%d0%b2%d0%b0%d0%b5%d1%82%d1%81%d1%8f-%d0%be%d0%b1%d1%80%d0%b0%d0%b1%d0%be%d1%82%d1%87%d0%b8%d0%ba-%d0%bf%d1%80%d0%b8-%d0%be%d1%82%d0%bf%d1%80%d0%b0%d0%b2%d0%ba%d0%b5-%d1%81%d0%b8%d0%b3%d0%bd%d0%b0%d0%bb%d0%b0-killpg#comment1633525_972905
В программе строится дерево из 8 процессов и нужен доступ ко всем. Пока файлы не созданы сигнал не отправляется, добавил код в вопрос.
https://ru.stackoverflow.com/questions/972905/%d0%9d%d0%b5-%d0%b2%d1%8b%d0%b7%d1%8b%d0%b2%d0%b0%d0%b5%d1%82%d1%81%d1%8f-%d0%be%d0%b1%d1%80%d0%b0%d0%b1%d0%be%d1%82%d1%87%d0%b8%d0%ba-%d0%bf%d1%80%d0%b8-%d0%be%d1%82%d0%bf%d1%80%d0%b0%d0%b2%d0%ba%d0%b5-%d1%81%d0%b8%d0%b3%d0%bd%d0%b0%d0%bb%d0%b0-killpg#comment1634019_972905
Изучив документацию, выяснил что printf нельзя использовать в обработчике, потому что это не "async-signal-safe function". Но адекватного ответа на вопрос о том, как вывести нужную мне информацию я не нашел.
https://ru.stackoverflow.com/questions/972905/%d0%9d%d0%b5-%d0%b2%d1%8b%d0%b7%d1%8b%d0%b2%d0%b0%d0%b5%d1%82%d1%81%d1%8f-%d0%be%d0%b1%d1%80%d0%b0%d0%b1%d0%be%d1%82%d1%87%d0%b8%d0%ba-%d0%bf%d1%80%d0%b8-%d0%be%d1%82%d0%bf%d1%80%d0%b0%d0%b2%d0%ba%d0%b5-%d1%81%d0%b8%d0%b3%d0%bd%d0%b0%d0%bb%d0%b0-killpg#comment1635203_972905
сигнал не получает сигнал - Это круто! Вы что имеете в виду?

Ответы - Не вызывается обработчик при отправке сигнала killpg / Не вызывается обработчик при отправке сигнала killpg

Sergey

24.04.2019 05:46:19

привожу код для двух дочерних процессов

pid = fork();

Что-то я вообще ничего не понимаю... Почему fork() стоит в ДОЧЕРНЕМ (!!!) процессе? А как же Вы порождаете дочерние процессы из главного?

Поскольку я всё-таки пишу ответ, то напомню о том, что порождать дочерние процессы должен родительский и именно с помощью fork() как-то так:

pid_t pid1, pid2;

// Порождаем первый дочерний процесс:
pid1 = fork();
if (pid1 < 0) {
    // Ошибка - завершаем работу
    printf(....
    return -1;
} else if (pid1 == 0) {
    // Мы в дочернем процессе
    execv(...); // Загружаем исполняемый модуль первого дочернего процесса
    // Если оказались здесь - ошибка
} else {
    printf("Запустили дочерний процесс с pid=%d\n", pid1);

}

// Порождаем второй дочерний процесс:
pid2 = fork();
if (pid2 < 0) {
    // Ошибка - завершаем работу
    printf(....
    return -1;
} else if (pid2 == 0) {
    // Мы в дочернем процессе
    execv(...); // Загружаем исполняемый модуль второго дочернего процесса
    // Если оказались здесь - ошибка
} else {
    printf("Запустили дочерний процесс с pid=%d\n", pid1);
}
https://ru.stackoverflow.com/questions/972905/%d0%9d%d0%b5-%d0%b2%d1%8b%d0%b7%d1%8b%d0%b2%d0%b0%d0%b5%d1%82%d1%81%d1%8f-%d0%be%d0%b1%d1%80%d0%b0%d0%b1%d0%be%d1%82%d1%87%d0%b8%d0%ba-%d0%bf%d1%80%d0%b8-%d0%be%d1%82%d0%bf%d1%80%d0%b0%d0%b2%d0%ba%d0%b5-%d1%81%d0%b8%d0%b3%d0%bd%d0%b0%d0%bb%d0%b0-killpg/974216#comment1635357_974216
В родительском процессе есть fork. Но т.к. задача построить дерево, то дочерний процесс также запускает процессы, а они в свою очередь запускают ещё.
https://ru.stackoverflow.com/questions/972905/%d0%9d%d0%b5-%d0%b2%d1%8b%d0%b7%d1%8b%d0%b2%d0%b0%d0%b5%d1%82%d1%81%d1%8f-%d0%be%d0%b1%d1%80%d0%b0%d0%b1%d0%be%d1%82%d1%87%d0%b8%d0%ba-%d0%bf%d1%80%d0%b8-%d0%be%d1%82%d0%bf%d1%80%d0%b0%d0%b2%d0%ba%d0%b5-%d1%81%d0%b8%d0%b3%d0%bd%d0%b0%d0%bb%d0%b0-killpg/974216#comment1635753_974216
@Rapzy они в свою очередь запускают ещё - я в Вашем коде насчитал 4 (!) уровня вложенности fork()... Мне кажется, что проще было бы написать рекурсивную ф-цию... Нет ? Но логику этих вложенных fork-ов я не осилил. :-( А уж понять кому и какой сигнал придёт, мне кажется, просто невозможно...
Является ответом!
Rapzy

24.04.2019 12:04:37

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

Осталось добавить флаг для выхода из цикла.

Полный код программы:

#include "stdio.h"
#include "stdlib.h"
#include "signal.h"
#include "string.h"
#include "unistd.h"
#include "libgen.h"
#include "ctype.h"
#include "sys/time.h"

//Дерево процессов
//1->2; 2->(3,4); 4->5; 3->6; 6->7; 7->8;
typedef struct {
        long tv_sec;
        long tv_usec;
    } timeval;

void waitChilds();
void createFile(int);
void deleteFiles();
int checkTree();
int readPid(int);
void getSignal(int);
long getTime();

char *progname;
int procNum, lastSender;

int main(int argc, char *argv[]) 
{
    argc += 0;
    progname = basename(argv[0]);
    signal(SIGINT, deleteFiles);
    pid_t pid = fork();
    if(pid == 0)//1
    {
        createFile(1);
        pid = fork();
        if(pid == 0)//2
        {
            createFile(2);
            pid = fork();
            if(pid==0)//4
            {
                createFile(4);
                pid = fork();
                if(pid==0)//5
                {
                    procNum = 5;
                    signal(SIGUSR1, getSignal);
                    setpgrp();
                    createFile(5);
                }
            }
            else if(pid > 0)
            {
                pid = fork();
                if(pid==0)//3
                {
                    createFile(3);
                }
                else
                {
                    pid = fork();
                    if (pid==0)//6
                    {
                        procNum = 6;
                        signal(SIGUSR1, getSignal);
                        setpgrp();
                        createFile(6);
                        pid = fork();
                        if(pid==0)//7
                        {
                            procNum = 7;
                            signal(SIGUSR1, getSignal);
                            setpgrp();
                            createFile(7);
                            pid = fork();
                            if(pid==0)//8
                            {
                                procNum = 8;
                                createFile(8);
                            }
                        }
                    }
                }
            }
        }
        else
        {
            while(!checkTree());
            procNum = 1;
            lastSender = 1;
            killpg(readPid(7), SIGUSR1);
            printf("%d %d %d послал USR1 %ld.\n", procNum, getpid(), getppid(), getTime());
        }
        for(;;);
    }
    else if(pid > 0)
    {
        wait(NULL);
        deleteFiles();
    }
    return 0;
}
void getSignal(int sig)
{
    char *sigName = strdup(sys_signame[sig]);
    int i = 0;
    while (sigName[i] != '\0') {
        sigName[i] = toupper((unsigned char) sigName[i]);
        i++;
    }
    printf("%d %d %d получил %s %ld.\n", procNum, getpid(), getppid(), sigName, getTime());
}
int checkTree()
{
    char path[30];
    int pid;
    FILE *f;
    for (int i = 1; i <= 8; i++)
    {
        snprintf(path, sizeof(path), "/tmp/Lab4_%d.txt",i);
        if((f = fopen(path, "r")) == NULL)              
            return 0;
        else 
        {
            fscanf (f, "%d", &pid);
            if(pid > 0)
                continue;
        }
    }
    return 1;
}
long getTime() {
    struct timeval tv;
    gettimeofday(&tv, NULL);
    return tv.tv_sec * (int)1e6 + tv.tv_usec;
}
int readPid(int num)
{
    char path[30];
    char pid[10];
    FILE *f;
    snprintf(path, sizeof(path), "/tmp/Lab4_%d.txt", num);
    if((f = fopen(path, "r")) == NULL)
    {
        fprintf(stderr, "%s: Couldn't open file %s.\n", progname, path);
        exit(1);
    }
    else
    {
        fgets(pid, sizeof(pid), f);
        return atoi(pid);
    }
}

void waitChilds()
{
    int wpid;
    while((wpid = wait(NULL)) > 0);
}
void createFile(int i)
{
    char path[30];
    snprintf(path, sizeof(path), "/tmp/Lab4_%d.txt", i);
    FILE *pidFile = fopen(path, "w");
    fprintf(pidFile, "%d", getpid());
    fclose(pidFile);
}

void deleteFiles()
{
    char path[30];
    for (int i = 1; i <= 8; i++)
    {
        kill(readPid(i),9);
        snprintf(path, sizeof(path), "/tmp/Lab4_%d.txt",i);
        remove(path);
    }
    exit(0);
}
Закрыть X