Использование сигналов и сигпайпа - PullRequest
4 голосов
/ 15 октября 2011

Я работаю над заданием, которое включает в себя написание программы для обработки данных (вычисления пи) с использованием форка (процессов), сигналов и выбора.

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

Я использую fork () в main (), чтобы назначить каждому процессу одну и ту же работу, отправив их рабочей функции.

void worker(int id) {
    .... (this piece of code is not relevant)

    if(write(pfd[id][1], &c, sizeof(c)) == -1)
        printf("Error occurred: %s\n",strerror(errno));

}

Как я могу реализовать сигналы в этой функции, чтобы поймать SIGPIPE и сделать егоеще раз напиши в трубу?

Спасибо!

1 Ответ

10 голосов
/ 15 октября 2011

Обычно вместо перехвата SIGPIPE его игнорируют, что приводит к сбою write с EPIPE вместо тихого завершения вашей программы.

Однако: Если вы получаете SIGPIPE при записи в канал, не пытайтесь снова. Это никогда не сработает. SIGPIPE означает, что у трубы нет считывателя - и если у трубы сейчас нет считывателя, у нее никогда не будет считывателя. (Подумайте об этом так: как труба без читателя получит ее? Это невозможно!)

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

Редактировать: Здесь есть два вопроса для ответа. Если вы не можете ответить на оба этих вопросов, не беспокойтесь о SIGPIPE.

  1. Что может заставить мою программу получить SIGPIPE? Единственный способ получить SIGPIPE - закрыть конец чтения канала. Это происходит, если происходит сбой процесса чтения или если он запрограммирован на закрытие канала. Если вы пишете сетевой сервер или общаетесь с неизвестным процессом, это может быть обычным явлением. Однако если вы пишете обе программы, обе работают локально, то это, вероятно, указывает на ошибку программирования.

  2. Что бы сделала моя программа, когда она перехватит SIGPIPE? Если вы пишете клиентский процесс, использующий канал для связи с сервером, то что вы должны делать с SIGPIPE? Вы не можете повторить попытку, и клиенты обычно не могут перезапустить сервер, к которому они подключены. Просто сделайте разумную вещь по умолчанию и позвольте SIGPIPE завершить вашу программу. Однако, если сервер отправляет данные клиенту, которым он управляет, и получает SIGPIPE, он может перезапустить клиент. Но это может быть очень плохой идеей - например, если клиент является детерминированным, он просто снова потерпит крах, и вы получите бесконечный цикл, а не простой сбой.

Таким образом, общий принцип здесь " Только перехватывать ошибки, которые вы готовы обработать. " Не перехватывайте ошибки только ради полноты. Просто позвольте им аварийно завершить работу вашей программы или вызвать сбой операции, и вы сможете вернуться и отладить ее позже.

Фрагмент кода: Это фрагмент кода из одного из моих проектов. Если вы запустите его, SIGPIPE не остановит ваш процесс. Вместо этого write сгенерирует ошибку EPIPE. Если вы пишете сетевой сервер, то EPIPE - это один из возможных способов внезапного отключения клиента.

void
ignore_sigpipe(void)
{
    struct sigaction act;
    int r;
    memset(&act, 0, sizeof(act));
    act.sa_handler = SIG_IGN;
    act.sa_flags = SA_RESTART;
    r = sigaction(SIGPIPE, &act, NULL);
    if (r)
        err(1, "sigaction");
}
...