Отправляет email-рассылки с помощью сервиса Sendsay
  Все выпуски  

Программирование в Unix-системах на Си


Служба Рассылок Subscribe.Ru

ПРОГРАММИРОВАНИЕ В UNIX-СИТЕМАХ

Выпуск No. 2 от 2 января 2002 г.


1.4 Программы и процессы

Программа это исполняемый файл, размещающийся в дисковом файле. Программа чита-ется в память и исполняется ядром.

Процессы и ID процесса

Выполняющийся экземпляр программы называется процессом. Некоторые операцион-ные системы используют термин "задача".

Каждому UNIX процессу дается уникальный числовой идентификатор, называемый идентификатором процесса (process ID).

Следующая программа печатает свой ID

Программа 1.4

#include <stdio.h>
#include <unistd.h>
int main()
{
  printf("Hello world from process ID %d\n",getpid());
  exit(0);
}

Мы скомпилировали эту программу в файл ex04 и выполнили его. Мы имеем:

$ ./ex04
hello world from process ID 851
$ ./ex04
hello world from process ID 855

1.5 Управление процессом

Существуют три основные функции, используемые для управления процессами: fork, exec и waitpid.

Работу этих функций мы рассмотрим на программе, которая читает команды со стандартного ввода и выполняет их. Существуют несколько основных моментов которые мы должны рассмотреть:

  • мы используем стандартную функцию ввода - вывода fgets для чтения одной строки со стандартного ввода. Когда мы введем символ конец файла (часто CTRL+D) в качестве первого символа строки, fgets возвращает нуль, цикл останавливается и процесс завершается.
  • Поскольку каждая строка, возвращаемая fgets, терминируется символом новой строки, за которой следует нулевой байт, мы можем использовать стандартную функцию strlen для вычисления длины строки, и затем заменяем символ новой строки нулевым байтом. Мы делаем так поскольку функция execlp ожидает, что ее аргумент завершается нулевым байтом, а не символом новой строки.

Теперь сама программа:

Программа 1.5

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include "errorx.h"

#define MAXLINE 4096
int main ()
{
  char  buf[MAXLINE];
  pid_t pid;
  int   status;

  printf("%% ");
  while (fgets(buf,MAXLINE,stdin)!=NULL) {
    buf[strlen(buf)-1]=0;    // заменяем символ новой строки нулем

    if((pid=fork()) <0)
        err_sys("fork error");
    else if(pid==0) {         /* дочерний */
         execlp(buf,buf, (char *)0);
         err_ret("couldn't execute: %s", buf);
  exit(127);
      }

    /* родительский */
    if( (pid=waitpid(pid, &status, 0))<0)
 err_sys("waitpid error");
    printf("%% ");
   }

 exit(0);
}

Не забудьте скомпилировать этот файл совместно с файлом errorx.c, который мы описывали в первом выпуске (gcc -o ex05 ex05.c error.c). Кроме того, вам надо добавить в него реализацию функции err_ret.

Вот она:

/* Non fatal error related to a system call.
   Print a mrssage and return
*/
void err_ret(const char *fmt, ...)
{
  va_list  ap;
  va_start (ap,fmt);
  err_doit(1, fmt, ap);
  va_end(ap);

  return;
}

А в файл errorx.h добавьте ее прототип:

void err_ret(const char *, ...);

  • Мы вызываем функцию fork, чтобы создать новый процесс. Новый про-цесс является копией старого и говорим старому, что он является родительским процессом, а вновь созданный - это дочерний. Функция fork возвращает неотрицательный ID нового дочернего процесса родителю, и возвращает нуль - дочернему процессу. Поскольку fork создает новый процесс, мы говорим, что она вызывается один раз (родительским процессом), но возвращает значение дважды (в родительский и в дочерний процессы).
  • В дочернем процессе мы вызываем функцию execlp, чтобы выполнить команду которую мы читаем со стандартного ввода. Она заменяет дочерний процесс новым программным файлом. Комбинация из fork, за которой следует exec, является тем, что некоторые операционный системы называют порождением нового процесса.
  • Так как дочерний процесс вызывает execlp, чтобы выполнить новый про-граммный файл, родитель ожидает, что дочерний процесс должен завершиться. Это делается вызовом waitpid, указывая какой процесс ждем. Функция waitpid также возвращает состояние завершения дочернего процесса (переменная status), но в этом примере мы ничего не делаем с этим значением. Мы могли бы проверить как завершился дочерний процесс.
  • Самым крупным ограничением этой программы является то, что мы не можем передать аргументы той команде, которую выполняем. Мы не можем, например, указать имя директории, чтобы посмотреть ее содержимое. Мы только можем выполнить команду ls в рабочей директории.

Если мы запустим эту программу, то получим следующие результаты:

$ ./ex05
% date
Fri Jun   7  15:30:54  MST  1991
% pwd
/home/baba_yaga/
% ^D
$

Полагаем, что мы скомпилировали программу в файл ex05.


Ведущий рассылки  Астероид

http://subscribe.ru/
E-mail: ask@subscribe.ru
Отписаться
Убрать рекламу

В избранное