В данный момент не удается просмотреть сообщение на форуме (неработающая ссылка?), Поэтому, возможно, это не ответ, но вы можете добавить DistinctRootEntityResultTransformer:
session.CreateCriteria(typeof(Product)
.Add(...)
.SetResultTransformer(new DistinctEntityRootTransformer())
Даже после выхода первой команды вашего конвейера (и thust закрывает stdout = ~ fdPipe [1]
), родительский элемент все еще имеет fdPipe [1]
open.
Таким образом, вторая команда конвейера имеет stdin = ~ fdPipe [0]
, который никогда не получает EOF, потому что другая конечная точка конвейера все еще открыта.
Вам необходимо создать новый канал (fdPipe)
для каждого |
и убедиться, что обе конечные точки в родительском элементе закрыты; т.е.
for cmd in cmds
if there is a next cmd
pipe(new_fds)
fork
if child
if there is a previous cmd
dup2(old_fds[0], 0)
close(old_fds[0])
close(old_fds[1])
if there is a next cmd
close(new_fds[0])
dup2(new_fds[1], 1)
close(new_fds[1])
exec cmd || die
else
if there is a previous cmd
close(old_fds[0])
close(old_fds[1])
if there is a next cmd
old_fds = new_fds
if there are multiple cmds
close(old_fds[0])
close(old_fds[1])
Кроме того, для большей безопасности следует обработать случай перекрытия fdPipe
и {STDIN_FILENO, STDOUT_FILENO}
перед выполнением любого из закрытия
и dup2
операций. Это может произойти, если кому-то удалось запустить вашу оболочку с закрытым stdin или stdout, и приведет к большой путанице с кодом здесь.
fdPipe1 fdPipe3
v v
cmd1 | cmd2 | cmd3 | cmd4 | cmd5
^ ^
fdPipe2 fdPipe4
В дополнение к тому, что вы закрываете конечные точки канала в родительском элементе, я пытался указать, что fdPipe1
, ] fdPipe2
и т. д. не может быть тем же pipe ()
.
/* suppose stdin and stdout have been closed...
* for example, if your program was started with "./a.out <&- >&-" */
close(0), close(1);
/* then the result you get back from pipe() is {0, 1} or {1, 0}, since
* fd numbers are always allocated from the lowest available */
pipe(fdPipe);
close(0);
dup2(fdPipe[0], 0);
Я знаю, что вы не используете close (0)
в вашем настоящий код, но последний абзац предупреждает вас, чтобы вы остерегались этого случая.
Следующее минимальное изменение в вашем коде заставляет его работать в конкретном случае отказа, который вы упомянули:
@@ -12,6 +12,4 @@ pid_t pid; - pipe(fdPipe); - while(1) { bBuffer = readline("Shell> "); @@ -29,4 +27,6 @@ } while(aPtr); + pipe(fdPipe); + for(i = 0; i < pCount; i++) { aCount = -1; @@ -72,4 +72,7 @@ } + close(fdPipe[0]); + close(fdPipe[1]); + for(i = 0; i < pCount; i++) { waitpid(lPids[i], &status, 0);
Это не будет работать более чем с одной командой в конвейере; для этого вам понадобится что-то вроде этого: (непроверено, так как вам нужно исправить и другие вещи)
@@ -9,9 +9,7 @@ int main(int argc, char *argv[]) { char *bBuffer, *sPtr, *aPtr = NULL, *pipeComms[NUMPIPES], *cmdArgs[10]; - int fdPipe[2], pCount, aCount, i, status, lPids[NUMPIPES]; + int fdPipe[2], fdPipe2[2], pCount, aCount, i, status, lPids[NUMPIPES]; pid_t pid; - pipe(fdPipe); - while(1) { bBuffer = readline("Shell> "); @@ -32,4 +30,7 @@ aCount = -1; + if (i + 1 < pCount) + pipe(fdPipe2); + do { aPtr = strsep(&pipeComms[i], " "); @@ -43,11 +44,12 @@ if(pid == 0) { - if(i == 0) { - close(fdPipe[0]); + if(i + 1 < pCount) { + close(fdPipe2[0]); - dup2(fdPipe[1], STDOUT_FILENO); + dup2(fdPipe2[1], STDOUT_FILENO); - close(fdPipe[1]); - } else if(i == 1) { + close(fdPipe2[1]); + } + if(i != 0) { close(fdPipe[1]); @@ -70,4 +72,17 @@ } } + + if (i != 0) { + close(fdPipe[0]); + close(fdPipe[1]); + } + + fdPipe[0] = fdPipe2[0]; + fdPipe[1] = fdPipe2[1]; + } + + if (pCount) { + close(fdPipe[0]); + close(fdPipe[1]); }
Одна из потенциальных проблем заключается в том, что cmdargs может содержать мусор в конце. Вы должны завершить этот массив нулевым указателем перед передачей его в execvp ().
Похоже, что grep принимает STDIN, так что это может не вызывать никаких проблем (пока).
После выполнения execvp () у вас должен быть выход с ошибкой - иногда он выйдет из строя.
exit(EXIT_FAILURE);
Как @ uncleo указывает, что список аргументов должен иметь нулевой указатель, указывающий на конец:
cmdArgs[aCount] = 0;
Мне непонятно, позволяете ли вы обеим программам работать бесплатно - похоже, вам нужно, чтобы первая программа в конвейере завершилась перед запуском во-вторых, что не является залогом успеха, если первая программа блокируется из-за переполнения канала.
У Джонатана верная идея. Вы полагаетесь на то, что первый процесс разветвляет все остальные. Каждый из них должен быть выполнен до завершения, прежде чем будет разветвлен следующий.
Вместо этого, разветвите процессы в цикле, как вы делаете, но дождитесь их выхода за пределы внутреннего цикла (в нижней части большого цикла для оболочки подсказка).
loop //for prompt
next prompt
loop //to fork tasks, store the pids
if pid == 0 run command
else store the pid
end loop
loop // on pids
wait
end loop
end loop
Я думаю, что ваши разветвленные процессы продолжат выполнение.
Попробуйте либо:
файловые дескрипторы из канала подсчитываются и увеличиваются с каждым разветвлением. для каждого форка вы должны закрыть оба дескриптора, чтобы уменьшить счетчик ссылок до нуля и позволить каналу закрыться. Я догадываюсь.