Испытывая затруднения из-за ветвления (), канал (), dup2 () и должностное лицо () в C

В данный момент не удается просмотреть сообщение на форуме (неработающая ссылка?), Поэтому, возможно, это не ответ, но вы можете добавить DistinctRootEntityResultTransformer:

session.CreateCriteria(typeof(Product)
    .Add(...)
    .SetResultTransformer(new DistinctEntityRootTransformer())
9
задан Ricardo Amaral 27 May 2009 в 19:23
поделиться

6 ответов

Даже после выхода первой команды вашего конвейера (и 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, и приведет к большой путанице с кодом здесь.

Edit

   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]);
         }
28
ответ дан 4 December 2019 в 06:57
поделиться

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

Похоже, что grep принимает STDIN, так что это может не вызывать никаких проблем (пока).

0
ответ дан 4 December 2019 в 06:57
поделиться

После выполнения execvp () у вас должен быть выход с ошибкой - иногда он выйдет из строя.

exit(EXIT_FAILURE);

Как @ uncleo указывает, что список аргументов должен иметь нулевой указатель, указывающий на конец:

cmdArgs[aCount] = 0;

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

4
ответ дан 4 December 2019 в 06:57
поделиться

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

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

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
1
ответ дан 4 December 2019 в 06:57
поделиться

Я думаю, что ваши разветвленные процессы продолжат выполнение.

Попробуйте либо:

  • Изменить его на 'return execvp'
  • Добавить 'exit (1);' после execvp
0
ответ дан 4 December 2019 в 06:57
поделиться

файловые дескрипторы из канала подсчитываются и увеличиваются с каждым разветвлением. для каждого форка вы должны закрыть оба дескриптора, чтобы уменьшить счетчик ссылок до нуля и позволить каналу закрыться. Я догадываюсь.

0
ответ дан 4 December 2019 в 06:57
поделиться
Другие вопросы по тегам:

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