Параллельная обработка не работает при использовании execv - PullRequest
0 голосов
/ 10 сентября 2018

Итак, я пытаюсь параллельный процесс и использовать execv. Проблема возникает в том, что когда я выполняю параллельный процесс, execv запускается только у одного потомка, а не у обоих. Я знаю, что оба дочерних процесса выполняются из-за операторов printf о pid.

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/wait.h>

  int main(int argc, char * argv[]) {
    char input[100];
    char * path[15];
    path[0] = "/bin/";
    char str[200];
    FILE * fp;
    if (argc == 2) {
      if ((fp = fopen(argv[1], "r")) == NULL) {
        printf("Error! opening file");
        // Program exits if file pointer returns NULL.
        exit(1);
      }
    }
    do {
      if (argc != 2) {
        printf("dash> ");
        fgets(input, 100, stdin);
      } else if (argc == 2) {
        if (fgets(input, 100, fp) == NULL)
          exit(0);
        printf(input);
      }
      input[strcspn(input, "\n")] = '\0';
      char * token = strtok(input, " ");
      int c = 0;
      if ((strcmp(token, "exit") != 0) && (strcmp(token, "cd") != 0) && (strcmp(token, "path") != 0)) {
        do {
          if (path[c] == NULL) {
            printf("p error");
            break;
          }
          strcpy(str, path[c]);
          strcat(str, token);
          c++;
        } while (access(str, X_OK) == -1);
      }
      if (strcmp(token, "exit") == 0) {
        exit(0);
      } else if (strcmp(token, "cd") == 0) {
        token = strtok(NULL, " ");
        if (chdir(token) == -1)
          printf("errorcd");
      } else if (strcmp(token, "path") == 0) {
        int counter = 0;
        while (path[counter] != NULL) {
          path[counter] = strtok(NULL, " ");
          counter++;
        }
      } else {
        char * myargs[15];
        char * par[15];
        myargs[0] = token;
        int counter = 0;
        int track = 0;
        int and = 1;
        while (myargs[counter] != NULL) // &&(strcmp(myargs[counter],">"))!=0){
        {
          counter++;
          myargs[counter] = strtok(NULL, " ");
        }
        int a = 0;
        int i = 0;
        int j = 0;
        int t = 0;
        // printf(myargs[i]);
        for (i = 0; i <= counter - 1; i++) {
          if (strcmp(myargs[i], "&") == 0)
            and++;
        }
        int temp = and + 1;
        // printf("No. %d",and);
        int rc[15];
        for (i = 0; i < and; i++) {
          a = 0;
          for (j = t; j <= counter - 1; j++) {
            par[a] = myargs[j];
            a++;
            if (strcmp(myargs[j], "&") == 0) {
              t = j + 1;
              break;
            }
          }

          if (and == 0)
            par[j + 1] = NULL;
          else
            par[j] = NULL;
          rc[i] = fork();
          if (rc[i] < 0) // fork failed
          {
            printf("Error");
            return 0;
          } else if (rc[i] == 0) // child process
          {
            printf("\nhello, I am child (pid:%d)\n", (int) getpid());
            if (j > 1) {
              if (strcmp(par[j - 2], ">") == 0) {
                int fd = open(par[j - 1], O_WRONLY | O_TRUNC | O_CREAT, S_IRUSR | S_IWUSR);
                dup2(fd, 1); // make stdout go to file
                dup2(fd, 2); // make stderr go to file - you may choose to not do this
                // or perhaps send stderr to another file
                // }
                par[counter - 2] = NULL;
              }
            }
            execv(str, par);
            printf("failed");
          }
        } // parent process
        int status;
        pid_t pid;

        while (temp > 0) {
          // waitpid(pid[i], 0, 0);
          pid = wait( & status);
          printf("Child with PID %ld exited with status 0x%x.\n", (long) pid, status);
          --temp; // TODO(pts): Remove pid from the pids array.
        }
      }
    } while (strcmp(input, "exit") != 0);
    return 0;
  }

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

dash> pwd & ls

hello, I am child (pid:40037)

hello, I am child (pid:40036)
/home/012/a/ax/axh161330/project1
Child with PID 40036 exited with status 0x0.
Child with PID 40037 exited with status 0x8b.
Child with PID -1 exited with status 0x8b.

Как видите, только одна команда execv выполнена (pwd), а другая никогда не выполнялась (ls). Первая команда всегда будет работать, а вторая - не будет.

1 Ответ

0 голосов
/ 11 сентября 2018

Эта адаптация вашего кода работает, по крайней мере, для pwd & ls в качестве командной строки. Одна из проблем заключалась в том, что цикл поиска пути к команде был в неправильном месте. Другая проблема заключалась в том, что цикл wait() был не в том месте. Другая проблема заключалась в том, что аргументы команды не были должным образом разделены.

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

Исходный код (exec29.c):

#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <unistd.h>

int main(int argc, char *argv[])
{
    char input[100];
    char *path[15];
    path[0] = "/bin/";
    FILE *fp;

    if (argc == 2)
    {
        if ((fp = fopen(argv[1], "r")) == NULL)
        {
            fprintf(stderr, "Error! opening file %s\n", argv[1]);
            exit(1);
        }
    }

    do
    {
        if (argc != 2)
        {
            printf("dash> ");
            if (fgets(input, 100, stdin) == NULL)
                exit(0);
        }
        else if (argc == 2)
        {
            if (fgets(input, 100, fp) == NULL)
                exit(0);
        }

        input[strcspn(input, "\n")] = '\0';
        printf("%s\n", input);
        char *token = strtok(input, " ");

        int temp = 0;
        if (strcmp(token, "exit") == 0)
        {
            exit(0);
        }
        else if (strcmp(token, "cd") == 0)
        {
            token = strtok(NULL, " ");
            if (chdir(token) == -1)
                fprintf(stderr, "error: cd %s\n", token);
        }
        else if (strcmp(token, "path") == 0)
        {
            int counter = 0;
            while (path[counter] != NULL)
            {
                path[counter] = strtok(NULL, " ");
                if (path[counter] != NULL)
                    printf("PATH: %s\n", path[counter]);
                counter++;
            }
        }
        else
        {
            char *myargs[15];
            char *par[15];
            myargs[0] = token;
            int counter = 0;
            int n_cmds = 1;
            while (myargs[counter] != NULL)
            {
                counter++;
                myargs[counter] = strtok(NULL, " ");
            }

            for (int i = 0; i < counter; i++)
                printf("%d: [[%s]]\n", i, myargs[i]);

            for (int i = 0; i < counter; i++)
            {
                if (strcmp(myargs[i], "&") == 0)
                    n_cmds++;
            }
            temp = n_cmds;
            printf("Num commands: %d\n", n_cmds);

            int t = 0;
            for (int i = 0; i < n_cmds; i++)
            {
                int a = 0;
                for (int j = t; j < counter; j++)
                {
                    if (strcmp(myargs[j], "&") == 0)
                    {
                        t = j + 1;
                        break;
                    }
                    par[a++] = myargs[j];
                }
                par[a] = NULL;
                int rc = fork();
                if (rc < 0)
                {
                    fprintf(stderr, "Error: fork failed\n");
                    return 1;
                }
                else if (rc == 0)
                {
                    char str[200];
                    printf("hello, I am child (pid:%d)\n", (int)getpid());
                    int c = 0;
                    do
                    {
                        if (path[c] == NULL)
                        {
                            fprintf(stderr, "path error - no PATH left\n");
                            break;
                        }
                        strcpy(str, path[c++]);
                        strcat(str, par[0]);
                    } while (access(str, X_OK) == -1);
                    printf("Cmd: [[%s]]\n", str);

                    char **args = par;
                    while (*args != NULL)
                        printf("[[%s]]\n", *args++);
                    fflush(stdout);
                    execv(str, par);
                    fprintf(stderr, "%s: failed\n", str);
                    exit(1);
                }
            }
        }

        while (temp > 0)
        {
            int status;
            pid_t pid = wait(&status);
            printf("%d: Child with PID %ld exited with status 0x%.4x.\n",
                   (int)getpid(), (long)pid, status);
            --temp;
        }

    } while (strcmp(input, "exit") != 0);
    return 0;
}

Имеется файл test-exec, содержащий:

pwd & ls
pwd -P & ls -l

Я получил пример вывода (exec29 test-exec):

pwd & ls
0: [[pwd]]
1: [[&]]
2: [[ls]]
Num commands: 2
hello, I am child (pid:4247)
Cmd: [[/bin/pwd]]
[[pwd]]
hello, I am child (pid:4248)
Cmd: [[/bin/ls]]
[[ls]]
/Users/jleffler/soq/so-5225-1783
4246: Child with PID 4247 exited with status 0x0000.
exec23.c    exec29      exec29.c    exec29.dSYM exec97.c    makefile    test-exec   test-exec-2
4246: Child with PID 4248 exited with status 0x0000.
pwd -P & ls -l
0: [[pwd]]
1: [[-P]]
2: [[&]]
3: [[ls]]
4: [[-l]]
Num commands: 2
hello, I am child (pid:4249)
Cmd: [[/bin/pwd]]
[[pwd]]
[[-P]]
hello, I am child (pid:4250)
Cmd: [[/bin/ls]]
[[ls]]
[[-l]]
/Users/jleffler/soq/so-5225-1783
4246: Child with PID 4249 exited with status 0x0000.
total 80
-rw-r--r--  1 jleffler  staff  3722 Sep 10 20:43 exec23.c
-rwxr-xr-x  1 jleffler  staff  9644 Sep 10 21:41 exec29
-rw-r--r--  1 jleffler  staff  4054 Sep 10 21:41 exec29.c
drwxr-xr-x  3 jleffler  staff    96 Sep 10 21:05 exec29.dSYM
-rw-r--r--  1 jleffler  staff  4549 Sep 10 21:45 exec97.c
-rw-r--r--  1 jleffler  staff   163 Sep 10 21:41 makefile
-rw-r--r--  1 jleffler  staff    24 Sep 10 21:47 test-exec
-rw-r--r--  1 jleffler  staff    34 Sep 10 21:38 test-exec-2
4246: Child with PID 4250 exited with status 0x0000.

Я удалил код, который, казалось, был связан с перенаправлением ввода-вывода; Я не удалял код, связанный с cd, exit или path, но я также не проверял их.

Один второстепенный, неясный момент: стандартный заголовок <iso646.h> определяет макрос and, который расширяется до &&. Лучше не использовать какие-либо имена из этого заголовка в качестве имен переменных, хотя действительно редко люди используют заголовок в C (но имена зарезервированы как «альтернативные представления» в C ++).

...