Параллельные процессы - PullRequest
       2

Параллельные процессы

2 голосов
/ 26 сентября 2010

Я хочу запустить несколько параллельных процессов в программе на Си.Программы будут принимать аргументы от пользователя и затем выполнять каждый аргумент как дочерний процесс.Я думаю, это означает, что все, что мне нужно сделать, это убедиться, что fork () выполняется исходным родительским процессом каждый раз, а затем каждый из получающихся дочерних процессов будет выполняться одновременно, а не последовательно.1002 * Правильно ли я считаю это?И кто-нибудь может дать мне знать, как мне это сделать?

Ответы [ 4 ]

2 голосов
/ 27 сентября 2010

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

Короткая версия:

Пожалуйста, сделайтеследующие изменения в вашей программе:

1. length = argc;               // in place of length = sizeof(argv);
2. execl(argv[i],argv[i],0);    // in place of execvp(argv[i],0);
3. #include <unistd.h>          // if you haven't already

Длинная версия:

(1) По переменной length, я полагаю, вы хотитечтобы получить общее количество аргументов.argv - это pointer-to-char-pointer, и как таковой это просто адрес памяти.Если вы распечатаете длину в вашей программе, вы заметите, что она всегда равна 4 (или каков бы ни был размер адреса памяти в вашей системе).

Итак, это:

length = sizeof(argv);

В действительности должно быть так:

length = argc;

argc содержит общее количество аргументов, переданных при выполнении процесса.Например,

./a.out /bin/ps /bin/ls

дает: argc = 3 (а не 2 , очень распространенная ошибка)

(2) Другая проблема с вашей программой, это вызов execvp.

Прототип для execvp выглядит следующим образом:

int execvp(const char *file, char *const argv[]);

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

В вашей программе вы используете:

execvp(argv[i],0);

Предположим, i=1 и argv[1] = "/bin/ls".Эта команда ищет исполняемый файл /bin/ls и передает ему нулевой указатель (0).Это может привести к следующей ошибке во время выполнения:

A NULL argv[0] was passed through an exec system call.

Ссылаясь на страницу руководства exec,

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

Хотя повторение имени файла не обязательно, вы, конечно, не должны передавать указатель NULL.Поскольку вы не хотите передавать какие-либо аргументы, я предлагаю вместо этого использовать следующий вызов execl:

execl(argv[i],argv[i],0);

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

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

2 голосов
/ 27 сентября 2010

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

Редактировать: Вы вычислили длину недопустимо.sizeof argv возвращает размер указателя на символ.Этот код

#include <stdio.h>
#include <unistd.h>

int main(int argc, char *argv[])
{
    int pid, i, length;

    length = argc;

    for(i = 1; i < length; i++)
    {
        printf("Argv[%d]: %s\n", i, argv[i]);  //error checking
        pid = fork();

        if(pid < 0)
        {
           printf("Fork failed.\n");
        }//end if
        else if(pid == 0)
        {
           execvp(argv[i], 0);
        }//end else if
        else
        {
           printf("Parent process (%d)\n", getpid());
        }//end if-else

    }//end for
    wait();
}//end main

, кажется, отлично работает для меня:

datan:~/src/c> ./a.out /bin/ps /bin/ps /bin/ps
Argv[1]: /bin/ps
Parent process (12748)
Argv[2]: /bin/ps
Parent process (12748)
Argv[3]: /bin/ps
Parent process (12748)
  PID TTY          TIME CMD
 6615 pts/5    00:00:00 bash
  PID TTY          TIME CMD
 6615 pts/5    00:00:00 bash
12627 pts/5    00:00:01 emacs
12748 pts/5    00:00:00 a.out
12749 pts/5    00:00:00 ps
12750 pts/5    00:00:00 ps
12751 pts/5    00:00:00 ps
datan:~/src/c> 12627 pts/5    00:00:01 emacs
12749 pts/5    00:00:00 ps
12750 pts/5    00:00:00 ps
  PID TTY          TIME CMD
 6615 pts/5    00:00:00 bash
12627 pts/5    00:00:01 emacs
12749 pts/5    00:00:00 ps

(хотя вам, вероятно, следует подождать всех детей, а не только любого, как этот код).

0 голосов
/ 26 сентября 2010

Я верю, что будет делать то, что вы хотите.Однако ...

fork() на самом деле не запускают несколько процессов в одной программе.Он запускает несколько копий одной и той же программы в разных процессах.Если между программами нет значительных совпадений, вы можете просто написать отдельные main() s для каждой.

0 голосов
/ 26 сентября 2010

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

Разве не было бы более эффективно использовать потоки для одновременной обработки?

...