Как предотвратить SIGPIPEs (или обработать их правильно),

Попробуйте следующее:

SELECT to_char (2/3::float, 'FM999999990.00');
-- RESULT: 0.67

Или просто:

SELECT round (2/3::DECIMAL, 2)::TEXT
-- RESULT: 0.67
240
задан Aristotle Pagaltzis 10 November 2008 в 05:28
поделиться

6 ответов

Вы обычно хотите проигнорировать SIGPIPE и обработать ошибку непосредственно в Вашем коде. Это вызвано тем, что обработчики сигналов в C имеют много ограничений на то, что они могут сделать.

самый портативный способ сделать это должно установить SIGPIPE обработчик к SIG_IGN. Это будет препятствовать любому сокету или передавать запись по каналу вызвать SIGPIPE сигнал.

Для игнорирования эти SIGPIPE сигнал используйте следующий код:

signal(SIGPIPE, SIG_IGN);

, Если Вы используете эти send() вызов, другая опция состоит в том, чтобы использовать MSG_NOSIGNAL опция, которая выключит SIGPIPE поведение на на основание вызова. Обратите внимание, что не все операционные системы поддерживают эти MSG_NOSIGNAL флаг.

Наконец, можно также хотеть рассмотреть SO_SIGNOPIPE флаг сокета, который может быть установлен с [1 111] в некоторых операционных системах. Это предотвратит SIGPIPE от того, чтобы быть вызванным записями только к сокетам, на которых это установлено.

236
ответ дан dvorak 4 November 2019 в 12:51
поделиться

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

На самом основанном на BSD (MacOS, FreeBSD...) системы, (принятие Вас используют C/C++), можно сделать это с:

int set = 1;
setsockopt(sd, SOL_SOCKET, SO_NOSIGPIPE, (void *)&set, sizeof(int));

С этим в действительности, вместо сгенерированного сигнала SIGPIPE, EPIPE будет возвращен.

149
ответ дан srdjan.veljkovic 4 November 2019 в 12:51
поделиться

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

15
ответ дан Jonathan Leffler 4 November 2019 в 12:51
поделиться

Или я должен просто поймать SIGPIPE с обработчиком и проигнорировать его?

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

Sam

6
ответ дан Sam Reynolds 4 November 2019 в 12:51
поделиться

Я очень опаздываю на вечеринку, но SO_NOSIGPIPE не переносится и может не работать в вашей системе (похоже, это вещь BSD).

Хорошей альтернативой, если вы используете, скажем, систему Linux без SO_NOSIGPIPE , было бы установить флаг MSG_NOSIGNAL в вашем вызове send (2).

Пример замены write (...) на send (..., MSG_NOSIGNAL) (см. Комментарий nobar )

char buf[888];
//write( sockfd, buf, sizeof(buf) );
send(    sockfd, buf, sizeof(buf), MSG_NOSIGNAL );
112
ответ дан 23 November 2019 в 03:12
поделиться

В этом сообщении я описал возможное решение для случая Solaris, когда недоступны ни SO_NOSIGPIPE, ни MSG_NOSIGNAL.

Вместо этого мы должны временно подавить SIGPIPE в текущем потоке, который выполняет код библиотеки. Вот как это сделать: чтобы подавить SIGPIPE, мы сначала проверяем, ожидает ли он. Если это так, это означает, что он заблокирован в этом потоке, и мы не должны ничего делать.Если библиотека генерирует дополнительный SIGPIPE, он будет объединен с ожидающим, и это не работает. Если SIGPIPE не ожидает обработки, мы блокируем его в этом потоке, а также проверяем, был ли он уже заблокирован. Тогда мы можем выполнять наши записи. Когда нам нужно восстановить SIGPIPE в исходное состояние, мы делаем следующее: если SIGPIPE изначально ожидал обработки, мы ничего не делаем. В противном случае мы проверяем, ожидает ли он сейчас. Если это так (что означает, что наши действия сгенерировали один или несколько SIGPIPE), мы ждем его в этом потоке, очищая, таким образом, его статус ожидания (для этого мы используем sigtimedwait () с нулевым таймаутом; это необходимо для предотвращения блокировки сценарий, при котором злонамеренный пользователь отправил SIGPIPE вручную всему процессу: в этом случае мы увидим его ожидающим, но другой поток может обработать его до того, как мы внесем изменения, чтобы дождаться его). После очистки состояния ожидания мы разблокируем SIGPIPE в этом потоке, но только если он не был заблокирован изначально.

Пример кода на https://github.com/kroki/XProbes/blob/1447f3d93b6dbf273919af15e59f35cca58fcc23/src/libxprobes.c#L156

29
ответ дан 23 November 2019 в 03:12
поделиться
Другие вопросы по тегам:

Похожие вопросы: