Ожидание сигнала из другого процесса с помощью sigwait()

Ожидание сигнала из другого процесса с помощью sigwait()

05.10.2016 10:03:39 Просмотров 26 Источник

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

main.c

int main(int argc, char** argv) {
  pid_t fork_pid = fork();
  if (fork_pid < 0) {
      exit(EXIT_FAILURE);
  }
  if (fork_pid == 0) {
      printf("Child will wait\n");
      sigset_t   set;
      int sig;
      sigemptyset(&set);                                                            
      sigaddset(&set, SIGUSR1);                                                                      
      sigwait(&set, &sig);
      printf("Child recive signal\n");
      exit(EXIT_SUCCESS);
  }
  if (fork_pid > 0) {
      // Do something before child
      kill(fork_pid,SIGUSR1);
      int res;
      wait(&res);
      printf("Child exit code: %d\n", res);
      // Do something after child
  }
}

При первом запуске всё хорошо сработало, но потом всё сломалось.

Вывод был таким

Child exit code: 30

Примечательно что константа SIGUSR1 на моей машине - 30! Я более чем уверен, что это связанно, но знаний явно не хватает, чтобы понять как это починить.

Заранее всем спасибо за ответ!

UPDATE:

Стало понятно, что дочерний процесс может быть не готов принимать сигнал во время вызова kill. Но как это чинить всё равно пока не ясно.

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

https://ru.stackoverflow.com/questions/574249/%d0%9e%d0%b6%d0%b8%d0%b4%d0%b0%d0%bd%d0%b8%d0%b5-%d1%81%d0%b8%d0%b3%d0%bd%d0%b0%d0%bb%d0%b0-%d0%b8%d0%b7-%d0%b4%d1%80%d1%83%d0%b3%d0%be%d0%b3%d0%be-%d0%bf%d1%80%d0%be%d1%86%d0%b5%d1%81%d1%81%d0%b0-%d1%81-%d0%bf%d0%be%d0%bc%d0%be%d1%89%d1%8c%d1%8e-sigwait#comment757083_574249
А никто не гарантирует, что родительский процесс выполнит kill после того как дочерний подготовится к приему сигнала. он может быть не готов еще и kill его убьет. необходимо использовать средства синхронизации процессов.
https://ru.stackoverflow.com/questions/574249/%d0%9e%d0%b6%d0%b8%d0%b4%d0%b0%d0%bd%d0%b8%d0%b5-%d1%81%d0%b8%d0%b3%d0%bd%d0%b0%d0%bb%d0%b0-%d0%b8%d0%b7-%d0%b4%d1%80%d1%83%d0%b3%d0%be%d0%b3%d0%be-%d0%bf%d1%80%d0%be%d1%86%d0%b5%d1%81%d1%81%d0%b0-%d1%81-%d0%bf%d0%be%d0%bc%d0%be%d1%89%d1%8c%d1%8e-sigwait#comment757090_574249
@Mike я догадывался что это так, но как это починить я всё равно не знаю. "средства синхронизации процессов" мне ни о чем не говорит, к сожалению. Можно подробнее?
https://ru.stackoverflow.com/questions/574249/%d0%9e%d0%b6%d0%b8%d0%b4%d0%b0%d0%bd%d0%b8%d0%b5-%d1%81%d0%b8%d0%b3%d0%bd%d0%b0%d0%bb%d0%b0-%d0%b8%d0%b7-%d0%b4%d1%80%d1%83%d0%b3%d0%be%d0%b3%d0%be-%d0%bf%d1%80%d0%be%d1%86%d0%b5%d1%81%d1%81%d0%b0-%d1%81-%d0%bf%d0%be%d0%bc%d0%be%d1%89%d1%8c%d1%8e-sigwait#comment757396_574249
@alexolut мютексы, семафоры используются при работе с потоками , а не с процесами.
https://ru.stackoverflow.com/questions/574249/%d0%9e%d0%b6%d0%b8%d0%b4%d0%b0%d0%bd%d0%b8%d0%b5-%d1%81%d0%b8%d0%b3%d0%bd%d0%b0%d0%bb%d0%b0-%d0%b8%d0%b7-%d0%b4%d1%80%d1%83%d0%b3%d0%be%d0%b3%d0%be-%d0%bf%d1%80%d0%be%d1%86%d0%b5%d1%81%d1%81%d0%b0-%d1%81-%d0%bf%d0%be%d0%bc%d0%be%d1%89%d1%8c%d1%8e-sigwait#comment757424_574249
@alexolut Да есть симофоры для процессов

Ответы - Ожидание сигнала из другого процесса с помощью sigwait() / Ожидание сигнала из другого процесса с помощью sigwait()

Yaroslav

06.10.2016 09:39:40

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

Это не большая программа устанавливающая обработчик сигнала на сигнал SIGUSR1 Сигнал SIGUSR1 можно послать командой kill -s SIGUSR1 <pid>

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

static volatile sig_atomic_t count = 0;
void handler_count(int signal_num)
{
  count++;
}
static int set_signals(void)
{
  struct sigaction act;
  sigset_t set;
  memset(&act, 0x0, sizeof(act));
  if(sigfillset(&set) < 0){
    printf("sigfillset failed\n");
    return 0;
  }
  act.sa_handler = handler_count;
  if(sigaction(SIGUSR1, &act, NULL) < 0){
    printf("sigaction failed SIGALRM\n");
    return 0;
  }
  if(sigemptyset(&set) < 0){
    printf("sigemptyset failed\n");
    return 0;
  }
  return 1;
}

int main(int argc,char * argv[])
{
  if(set_signals() == 0)
    return 0;
  for(;;){
    pause();
    if(count == 5){
      break;
    }
    printf("count :> %d\n",count);
  }
  return 0;
}
Является ответом!
sercxjo

10.10.2016 12:46:29

Значение статуса содержит не только код возврата от exit(), но и причину завершения в одной переменной, чтобы отделить одно от другого существуют макросы WIFEXITED, WEXITSTATUS и т.д., см. пример ниже. В вашем случае статус действительно содержал номер прервавшего сигнала.

Если сигнал приходит в sigwait(), функция-обработчик не вызывается (проверял в Linux). Но если обработчик не устанавливать, происходит реакция по-умолчанию, в данном случае — завершение программы. Если игнорировать сигнал (signal(SIGUSR1, SIG_IGN)), sigwait не прерывается сигналом. Поэтому функция-обработчик всё-таки нужна, кроме того она нужна на случай, если сигнал придёт до вызова sigwait().

Для ожидания родительским процессом готовности потомка можно использовать трубу.

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

volatile int sigcount;
void handler_count(int signal_num)
{
    sigcount++;
}
int main(int argc, char **argv)
{
    int pipefd[2];
    pipe(pipefd);
    pid_t fork_pid = fork();
    if (fork_pid < 0) {
        exit(EXIT_FAILURE);
    }
    if (fork_pid == 0) {
        printf("Child will wait\n");
        sigset_t set;
        int sig;
        signal(SIGUSR1, &handler_count);
        close(pipefd[0]);
        sigemptyset(&set);
        sigaddset(&set, SIGUSR1);
        write(pipefd[1], "", 1); // процесс готов к приёму сигнала
        close(pipefd[1]);
        sigwait(&set, &sig); // если заменить на  pause(); счётчик увеличивается
        printf("Child recived signal, sigcount=%d\n", sigcount);
        exit(EXIT_SUCCESS);
    }
    if (fork_pid > 0) {
        char c;
        close(pipefd[1]);
        read(pipefd[0], &c, 1); // ожидание готовности потомка
        close(pipefd[0]);
        kill(fork_pid, SIGUSR1);
        int status;
        if (wait(&status)<0) {
            perror("wait");
        } else if (WIFEXITED(status)) {
            printf("Child exited, status=%d\n", WEXITSTATUS(status));
        } else if (WIFSIGNALED(status)) {
            printf("Child killed by signal %d\n", WTERMSIG(status));
        } else if (WIFSTOPPED(status)) {
            printf("Child stopped by signal %d\n", WSTOPSIG(status));
        } else if (WIFCONTINUED(status)) {
            printf("Child continued\n");
        }
    }
}
Закрыть X