SIGPIPE в простой двухпроцессной программе
У меня есть простая настройка для вилки и трубы, которые я использовал раньше. Но на этот раз я получаю SIGPIPE
в моем write
вызов. Вот код
int fd[2];
int pid;
if (pipe(fd) == -1) {
perror("pipe init error");
exit(1);
}
// signal(SIGPIPE, SIG_IGN);
if ((pid = fork()) < -1) {
perror("fork error"); exit(1);
}
// parent
else if (pid > 0) {
close(fd[0]);
write(fd[1], "WHAT", MAXWORD); //SIGPIPE here
close(fd[1]);
int status;
wait(&status);
}
// child
else {
close(fd[1]);
// void foo(char *dirname, int in, int out);
// foo takes a path, reads from fd 'in' and outputs to 'fd' out
foo("./some/path", fd[0], 1);
close(fd[0]);
}
Вот функция foo:
void foo(char *dirname, int in, int out){
int string_length;
char word[MAXWORD];
// to get rid of \n
char* sep;
sep = malloc(sizeof(char));
// read from piped stdin until it's closed
while ((string_length = read(in, word, MAXWORD)) > 0){
// get rid of \n
sep = strchr(word, '\n');
*sep = '\0';
printf("THe word is: %s\n", word);
}
}
1 ответ
Если вы получаете SIGPIPE, когда пишете в канал, это означает, что нет процесса, который может читать из канала: ни текущий процесс (вы закрыли конец чтения канала - это хорошо; вместо этого вы будете заблокированы). мертвых, если вы не закрыли его), ни другой (дочерний) процесс.
Поскольку вы не показали, что функция foo()
да, мы не можем больше рассказать вам о том, что не так.
Теперь, когда foo()
было добавлено, не понятно в чем дело. Есть проблемы, но большинство не показывают пробки.
- аргументация
dirname
не используется. - аргументация
out
не используется. - Вы теряете память, выделенную для
sep
в петле. - Вы не гарантируете, что строка, прочитанная из канала, заканчивается нулем. Это может привести к сбоям, что, в свою очередь, приведет к сбою записи.
Я подозреваю, что пункт 4 является неотложной проблемой; другие - больше вопросов аккуратности.
Отмечу, что в основном коде у вас есть:
write(fd[1], "WHAT", MAXWORD); //SIGPIPE here
Если не MAXWORD
либо 4, либо 5, вы на пути проигрыша; Вы должны написать только 4 или 5 символов.
В сочетании с read()
... чтение будет пытаться прочитать байты MAXWORD, но может получить меньше. Однако нет никаких признаков того, что записанные данные содержат новую строку, поэтому поиск новой строки во входных данных не будет работать надежно. Однако эта проблема должна проявиться и после успешной записи канала, а не до этого.
Замечу, что переменная int fd_parent_write_word[2];
не используется, и код использует переменную int fd[2]
без объявления этого.
Это неприятно, когда то, что вы анализируете, не является SSCCE ( короткий, самостоятельный, правильный пример). Намного проще, когда тестовый пример был превращен в простую программу, которую можно скомпилировать и запустить с отправителем, который уверен, что проблема воспроизводится вместе с ним.
Этот код SSCCE компилируется чисто и работает нормально:
#include <assert.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
enum { MAXWORD = 5 };
static void foo(int in);
static void he_who_pays_the_piper(int signum)
{
assert(signum == SIGPIPE);
const char msg[] = "Received signal SIGPIPE\n";
write(2, msg, sizeof(msg)-1);
exit(1);
}
int main(void)
{
int fd[2];
int pid;
if (pipe(fd) == -1) {
perror("pipe init error");
exit(1);
}
signal(SIGPIPE, he_who_pays_the_piper);
if ((pid = fork()) < -1) {
perror("fork error"); exit(1);
}
else if (pid > 0) {
close(fd[0]);
write(fd[1], "WHAT", MAXWORD); //SIGPIPE here
close(fd[1]);
int status;
pid = wait(&status);
printf("Got status 0x%04X from %d\n", status, pid);
}
else {
close(fd[1]);
foo(fd[0]);
close(fd[0]);
}
return 0;
}
static void foo(int in)
{
int string_length;
char word[MAXWORD];
while ((string_length = read(in, word, MAXWORD)) > 0)
printf("The word is: %.*s\n", string_length, word);
}
Пример вывода:
The word is: WHAT
Got status 0x0000 from 49458
Обратите внимание, что это работает, потому что '\0'
в конце строки WHAT
записывается в трубу и читается из трубы. Чаще всего вы не пишете строки, включая завершающий '\0'
,