Архив документации OpenNet.ru / Раздел "Программирование, языки" / Индекс
Оглавление

Глава 6. МНОГОЗАДАЧНОСТЬ

6.1. Основы многозадачности в Linux
6.2. Использование getpid() и getppid()
6.3. Порождение процесса
6.4. Замена образа процесса

6.1. Основы многозадачности в Linux

Эта глава открывает большую и очень важную для Linux-программиста тему многозадачности. Описать все сразу не получится, поэтому мы будем неоднократно возвращаться к многозадачности в последующих главах книги. Пристегните ремни покрепче!

Наберите в своей оболочке следующую команду:


$ ps -e

На экран будут выведен список всех работающих в системе процессов. Если хотите посчитать количество процессов, наберите что-нибудь, набодобие этого:


$ ps -e --no-headers | nl | tail -n 1
74 4650 pts/0 00:00:00 tail
$

Первое число - это количество работающих в системе процессов. Пользователи KDE могут воспользоваться программой kpm, а пользователи Gnome - программой gnome-system-monitor для получения информации о процессах. На то он и Linux, чтобы позволять пользователю делать одно и то же разными способами.

Возникает вопрос: "Что такое процесс?". Процессы в Linux, как и файлы, являются аксиоматическими понятиями. Иногда процесс отождествляют с запущенной программой, однако это не всегда так. Будем считать, что процесс - это рабочая единица системы, которая выполняет что-то. Многозадачность - это возможность одновременного сосуществования нескольких процессов в одной системе.

Linux - многозадачная операционная система. Это означает что процессы в ней работают одновременно. Естественно, это условная формулировка. Ядро Linux постоянно переключает процессы, то есть время от времени дает каждому из них сколько-нибудь процессорного времени. Переключение происходит довольно быстро, поэтому нам кажется, что процессы работают одновременно.

Одни процессы могут порождать другие процессы, образовывая древовидную структуру. Порождающие процессы называются родителями или родительскими процессами, а порожденные - потомками или дочерними процессами. На вершине этого "дерева" находится процесс init, который порождается автоматически ядром в процесссе загрузки системы.

К каждому процессу в системе привязана пара целых неотрицательных чисел: идентификатор процесса PID (Process IDentifier) и идентификатор родительского процесса PPID (Parent Process IDentifier). Для каждого процесса PID является уникальным (в конкретный момент времени), а PPID равен идентификатору процесса-родителя. Если ввести в оболочку команду ps -ef, то на экран будет выведен список процессов со значениями их PID и PPID (вторая и третья колонки соотв.). Вот, например, что творится у меня в системе:


$ ps -ef
UID        PID  PPID  C STIME TTY          TIME CMD
root         1     0  0 06:16 ?        00:00:01 init [3]
root         2     1  0 06:16 ?        00:00:00 [migration/0]
root         3     1  0 06:16 ?        00:00:00 [ksoftirqd/0]
root         4     1  0 06:16 ?        00:00:00 [watchdog/0]
root         5     1  0 06:16 ?        00:00:00 [migration/1]
root         6     1  0 06:16 ?        00:00:00 [ksoftirqd/1]
root         7     1  0 06:16 ?        00:00:00 [watchdog/1]
root         8     1  0 06:16 ?        00:00:00 [events/0]
root         9     1  0 06:16 ?        00:00:00 [events/1]
root        10     1  0 06:16 ?        00:00:00 [khelper]
root        11     1  0 06:16 ?        00:00:00 [kthread]
root        35    11  0 06:16 ?        00:00:00 [kblockd/0]
root        36    11  0 06:16 ?        00:00:00 [kblockd/1]
root        37    11  0 06:16 ?        00:00:00 [kacpid]
root       216    11  0 06:16 ?        00:00:00 [kseriod]
root       244    11  0 06:16 ?        00:00:00 [pdflush]
root       245    11  0 06:16 ?        00:00:00 [pdflush]
root       246    11  0 06:16 ?        00:00:00 [kswapd0]
root       247    11  0 06:16 ?        00:00:00 [aio/0]
root       248    11  0 06:16 ?        00:00:00 [aio/1]
root       395    11  0 06:16 ?        00:00:00 [ata/0]
root       396    11  0 06:16 ?        00:00:00 [ata/1]
root       397    11  0 06:16 ?        00:00:00 [ata_aux]
root       407    11  0 06:16 ?        00:00:00 [scsi_eh_0]
root       408    11  0 06:16 ?        00:00:00 [scsi_eh_1]
root       409    11  0 06:16 ?        00:00:00 [scsi_eh_2]
root       410    11  0 06:16 ?        00:00:00 [scsi_eh_3]
root       422    11  0 06:17 ?        00:00:00 [scsi_eh_4]
root       423    11  0 06:17 ?        00:00:00 [scsi_eh_5]
root      1406    11  0 06:17 ?        00:00:00 [kjournald]
root      1443    11  0 06:17 ?        00:00:00 [ksuspend_usbd]
root      1446    11  0 06:17 ?        00:00:00 [khubd]
root      1462     1  0 06:17 ?        00:00:00 /sbin/udevd --daemon
root      3230    11  0 06:17 ?        00:00:00 [kpsmoused]
nn        3498 11591  0 12:06 pts/1    00:00:08 kate 006.html
nn        3984 11591  0 12:08 pts/1    00:00:03 kate 007.html
nn        4026     1  0 12:09 ?        00:00:00 kio_uiserver [kdeinit]
nobody    4563  6054  0 09:15 ?        00:00:00 /usr/sbin/httpd -k start
root      4652    11  0 06:17 ?        00:00:00 [khpsbpkt]
root      4785    11  0 06:17 ?        00:00:00 [pccardd]
root      4786    11  0 06:17 ?        00:00:00 [tifm/0]
root      4840    11  0 06:17 ?        00:00:00 [knodemgrd_0]
root      4849    11  0 06:17 ?        00:00:00 [kmmcd]
nn        5504  6133  0 12:17 ?        00:00:00 konsole [kdeinit]
nn        5505  5504  0 12:17 pts/0    00:00:00 /bin/bash
root      5807    11  0 06:17 ?        00:00:00 [kjournald]
root      5810    11  0 06:17 ?        00:00:00 [kjournald]
root      5970     1  0 06:17 ?        00:00:00 /usr/sbin/syslog-ng
root      5973     1  0 06:17 ?        00:00:00 /usr/sbin/crond
root      5981     1  0 06:17 ?        00:00:00 /bin/sh /usr/bin/mysqld_safe
root      5983    11  0 06:17 ?        00:00:00 [loop0]
root      5984     1  0 06:17 tty1     00:00:00 /bin/login --
root      5985     1  0 06:17 tty2     00:00:00 /sbin/agetty 38400 vc/2 linux
root      5986     1  0 06:17 tty3     00:00:00 /sbin/agetty 38400 vc/3 linux
root      5987     1  0 06:17 tty4     00:00:00 /sbin/agetty 38400 vc/4 linux
root      5988     1  0 06:17 tty5     00:00:00 /sbin/agetty 38400 vc/5 linux
root      5989     1  0 06:17 tty6     00:00:00 /sbin/agetty 38400 vc/6 linux
mysql     6026  5981  0 06:17 ?        00:00:00 /usr/sbin/mysqld --basedir=/usr
root      6029     1  0 06:17 ?        00:00:00 /usr/sbin/cupsd
postgres  6033     1  0 06:17 ?        00:00:00 /usr/bin/postmaster -D /var/lib/
root      6046     1  0 06:17 ?        00:00:00 /usr/bin/mpd /etc/mpd.conf
root      6048  6046  0 06:17 ?        00:00:04 /usr/bin/mpd /etc/mpd.conf
root      6049  6048  0 06:17 ?        00:00:01 /usr/bin/mpd /etc/mpd.conf
root      6054     1  0 06:17 ?        00:00:00 /usr/sbin/httpd -k start
postgres  6059  6033  0 06:17 ?        00:00:00 postgres: writer process
postgres  6060  6033  0 06:17 ?        00:00:00 postgres: stats buffer process
postgres  6061  6060  0 06:17 ?        00:00:00 postgres: stats collector proces
nobody    6062  6054  0 06:17 ?        00:00:00 /usr/sbin/httpd -k start
nobody    6063  6054  0 06:17 ?        00:00:00 /usr/sbin/httpd -k start
nobody    6064  6054  0 06:17 ?        00:00:00 /usr/sbin/httpd -k start
nobody    6065  6054  0 06:17 ?        00:00:00 /usr/sbin/httpd -k start
nobody    6066  6054  0 06:17 ?        00:00:00 /usr/sbin/httpd -k start
nn        6067  5984  0 06:28 tty1     00:00:00 -bash
nn        6071  6067  0 06:28 tty1     00:00:00 xinit
root      6072  6071  1 06:28 tty7     00:04:28 X :0
root      6090  6072  0 06:28 tty7     00:00:00 X :0
nn        6092  6071  0 06:28 tty1     00:00:00 /bin/sh /opt/kde/bin/startkde
nn        6113     1  0 06:28 ?        00:00:00 /usr/bin/gpg-agent --daemon
nn        6116     1  0 06:28 ?        00:00:00 /usr/bin/ssh-agent -s
root      6132     1  0 06:28 tty1     00:00:00 start_kdeinit --new-startup +kcm
nn        6133     1  0 06:28 ?        00:00:00 kdeinit Running...
nn        6136     1  0 06:28 ?        00:00:00 dcopserver [kdeinit] --nosid
nn        6138  6133  0 06:28 ?        00:00:00 klauncher [kdeinit] --new-startu
nn        6140     1  0 06:28 ?        00:00:21 kded [kdeinit] --new-startup
nn        6145  6092  0 06:28 tty1     00:00:00 kwrapper ksmserver
nn        6147     1  0 06:28 ?        00:00:00 ksmserver [kdeinit]
nn        6148  6133  0 06:28 ?        00:00:05 kwin [kdeinit] -session 106e6e64
nn        6150     1  0 06:28 ?        00:00:00 knotify [kdeinit]
nn        6152     1  0 06:28 ?        00:00:02 kdesktop [kdeinit]
nn        6154     1  0 06:28 ?        00:00:11 kicker [kdeinit]
nn        6160     1  0 06:28 ?        00:00:00 kaccess [kdeinit]
nn        6163     1  0 06:28 ?        00:00:00 kmix [kdeinit] -session 106e6e64
nn        6164  6133  0 06:28 ?        00:00:00 konqueror [kdeinit] --preload
nn        6166  6133  0 06:28 ?        00:00:00 konqueror [kdeinit] --preload
nn        6242  6133  0 06:29 ?        00:00:04 /usr/bin/python /usr/bin/sonata
nn        6251  6133  0 09:24 ?        00:00:00 kio_file [kdeinit] file /tmp/kso
nn        6256     1  0 06:29 ?        00:00:00 dbus-launch --autolaunch 27b9194
nn        6257     1  0 06:29 ?        00:00:00 /usr/bin/dbus-daemon --fork --pr
nn        8952     1  0 06:43 ?        00:00:40 kopete
nn       10460  6133  0 12:43 ?        00:00:01 konsole [kdeinit]
nn       10461 10460  0 12:43 pts/2    00:00:00 /bin/bash
nn       11454 10461  0 12:49 pts/2    00:00:00 ps -ef
nn       11590  6133  0 06:58 ?        00:00:03 konsole [kdeinit]
nn       11591 11590  0 06:58 pts/1    00:00:00 /bin/bash
nn       13609  6133  0 07:07 ?        00:00:00 /bin/sh /usr/bin/firefox
nn       13620 13609  0 07:07 ?        00:00:00 /bin/sh /opt/firefox/run-mozilla
nn       13625 13620  1 07:07 ?        00:05:52 /opt/firefox/firefox-bin
nn       13632     1  0 07:07 ?        00:00:00 /opt/gnome/libexec/gconfd-2 12
nobody   24957  6054  0 08:09 ?        00:00:00 /usr/sbin/httpd -k start

Надо отметить, что процесс init всегда имеет идентификатор 1 и PPID равный 0. Хотя в реальности процесса с идентификатором 0 не существует. Дерево процессов можно также пресставить в наглядном виде при помощи опции --forest программы ps:


$ ps -e --forest
  PID TTY          TIME CMD
    1 ?        00:00:01 init
    2 ?        00:00:00 migration/0
    3 ?        00:00:00 ksoftirqd/0
    4 ?        00:00:00 watchdog/0
    5 ?        00:00:00 migration/1
    6 ?        00:00:00 ksoftirqd/1
    7 ?        00:00:00 watchdog/1
    8 ?        00:00:00 events/0
    9 ?        00:00:00 events/1
   10 ?        00:00:00 khelper
   11 ?        00:00:00 kthread
   35 ?        00:00:00  \_ kblockd/0
   36 ?        00:00:00  \_ kblockd/1
   37 ?        00:00:00  \_ kacpid
  216 ?        00:00:00  \_ kseriod
  244 ?        00:00:00  \_ pdflush
  245 ?        00:00:00  \_ pdflush
  246 ?        00:00:00  \_ kswapd0
  247 ?        00:00:00  \_ aio/0
  248 ?        00:00:00  \_ aio/1
  395 ?        00:00:00  \_ ata/0
  396 ?        00:00:00  \_ ata/1
  397 ?        00:00:00  \_ ata_aux
  407 ?        00:00:00  \_ scsi_eh_0
  408 ?        00:00:00  \_ scsi_eh_1
  409 ?        00:00:00  \_ scsi_eh_2
  410 ?        00:00:00  \_ scsi_eh_3
  422 ?        00:00:00  \_ scsi_eh_4
  423 ?        00:00:00  \_ scsi_eh_5
 1406 ?        00:00:00  \_ kjournald
 1443 ?        00:00:00  \_ ksuspend_usbd
 1446 ?        00:00:00  \_ khubd
 3230 ?        00:00:00  \_ kpsmoused
 4652 ?        00:00:00  \_ khpsbpkt
 4785 ?        00:00:00  \_ pccardd
 4786 ?        00:00:00  \_ tifm/0
 4840 ?        00:00:00  \_ knodemgrd_0
 4849 ?        00:00:00  \_ kmmcd
 5807 ?        00:00:00  \_ kjournald
 5810 ?        00:00:00  \_ kjournald
 5983 ?        00:00:00  \_ loop0
 1462 ?        00:00:00 udevd
 5970 ?        00:00:00 syslog-ng
 5973 ?        00:00:00 crond
 5981 ?        00:00:00 mysqld_safe
 6026 ?        00:00:00  \_ mysqld
 5984 tty1     00:00:00 login
 6067 tty1     00:00:00  \_ bash
 6071 tty1     00:00:00      \_ xinit
 6072 tty7     00:04:40          \_ X
 6090 tty7     00:00:00          |   \_ X
 6092 tty1     00:00:00          \_ startkde
 6145 tty1     00:00:00              \_ kwrapper
 5985 tty2     00:00:00 agetty
 5986 tty3     00:00:00 agetty
 5987 tty4     00:00:00 agetty
 5988 tty5     00:00:00 agetty
 5989 tty6     00:00:00 agetty
 6029 ?        00:00:00 cupsd
 6033 ?        00:00:00 postmaster
 6059 ?        00:00:00  \_ postmaster
 6060 ?        00:00:00  \_ postmaster
 6061 ?        00:00:00      \_ postmaster
 6046 ?        00:00:00 mpd
 6048 ?        00:00:04  \_ mpd
 6049 ?        00:00:01      \_ mpd
 6054 ?        00:00:00 httpd
 6062 ?        00:00:00  \_ httpd
 6063 ?        00:00:00  \_ httpd
 6064 ?        00:00:00  \_ httpd
 6065 ?        00:00:00  \_ httpd
 6066 ?        00:00:00  \_ httpd
24957 ?        00:00:00  \_ httpd
 4563 ?        00:00:00  \_ httpd
 6113 ?        00:00:00 gpg-agent
 6116 ?        00:00:00 ssh-agent
 6132 tty1     00:00:00 start_kdeinit
 6133 ?        00:00:00 kdeinit
 6138 ?        00:00:00  \_ klauncher
 6148 ?        00:00:05  \_ kwin
 6164 ?        00:00:00  \_ konqueror
 6166 ?        00:00:00  \_ konqueror
 6242 ?        00:00:04  \_ sonata
11590 ?        00:00:03  \_ konsole
11591 pts/1    00:00:00  |   \_ bash
 3498 pts/1    00:00:09  |       \_ kate
 3984 pts/1    00:00:03  |       \_ kate
13609 ?        00:00:00  \_ firefox
13620 ?        00:00:00  |   \_ run-mozilla.sh
13625 ?        00:05:56  |       \_ firefox-bin
 6251 ?        00:00:00  \_ kio_file
 5504 ?        00:00:00  \_ konsole
 5505 pts/0    00:00:00  |   \_ bash
10460 ?        00:00:01  \_ konsole
10461 pts/2    00:00:00      \_ bash
12140 pts/2    00:00:00          \_ ps
 6136 ?        00:00:00 dcopserver
 6140 ?        00:00:21 kded
 6147 ?        00:00:00 ksmserver
 6150 ?        00:00:00 knotify
 6152 ?        00:00:02 kdesktop
 6154 ?        00:00:11 kicker
 6160 ?        00:00:00 kaccess
 6163 ?        00:00:00 kmix
 6256 ?        00:00:00 dbus-launch
 6257 ?        00:00:00 dbus-daemon
 8952 ?        00:00:40 kopete
13632 ?        00:00:00 gconfd-2
 4026 ?        00:00:00 kio_uiserver

Если вызвать программу ps без аргументов, то будет выведен список процессов, принадлежащих текущей группе, то есть работающих под текущим терминалом. О том, что такое терминалы и группы процессов, будет рассказано в последующих главах.

6.2. Использование getpid() и getppid()

Процесс может узнать свой идентификатор (PID), а также родительский идентификатор (PPID) при помощи системных вызовов getpid() и getppid().

Системные вызовы getpid() и getppid() имеют следующие прототипы:


pid_t getpid (void);
pid_t getppid (void);

Для использования getpid() и getppid() в программу должны быть включены директивой #include заголовочные файлы unistd.h и sys/types.h (для типа pid_t). Вызов getpid() возвращает идентификатор текущего процесса (PID), а getppid() возвращает идентификатор родителя (PPID). pid_t - это целый тип, размерность которого зависит от конкретной системы. Значениями этого типа можно оперировать как обычными целыми числами типа int.

Рассмотрим теперь простую программу, которая выводит на экран PID и PPID, а затем "замирает" до тех пор, пока пользователь не нажмет <Enter>.


/* getpid.c */

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>

int main (void)
{
        pid_t pid, ppid;

        pid = getpid ();
        ppid = getppid ();

        printf ("PID: %d\n", pid);
        printf ("PPID: %d\n", ppid);

        fprintf (stderr, "Press <Enter> to exit...");
        getchar ();
        return 0;
}

Проверим теперь, как работает эта программа. Для этого откомпилируем и запустим ее:


$ gcc -o getpid getpid.c
$ ./getpid
PID: 27784
PPID: 6814
Press <Enter> to exit...

Теперь, не нажимая <Enter>, откроем другое терминальное окно и проверим, правильность работы системных вызовов getpid() и getppid():


$ ps -ef | grep getpid
nn       27784  6814  0 01:05 pts/0    00:00:00 ./getpid
nn       28249 28212  0 01:07 pts/1    00:00:00 grep getpid

6.3. Порождение процесса

Как уже говорилось ранее, процесс в Linux - это нечто, выполняющее программный код. Этот код называют образом процесса (process image). Рассмотрим простой пример, когда вы находитесь в оболочке bash и выполняете команду ls. В этом случае происходит следующее. Образ программы-оболочки bash выполняется в процессе #1. Затем вы вводите команду ls, и оболочка определяет, что нужно запустить внешнюю программу (/bin/ls). Тогда процесс #1 создает свою почти точную копию, процесс #2, который выполняет тот же самый программный код. После этого процесс #2 заменяет свой текущий образ (оболочку) другим образом (программой /bin/ls). В итоге получаем отдельный процесс, выполняющий отдельную программу.

"К чему такая путаница?" - спросите вы. Зачем сначала "клонировать" процесс, а затем заменять в нем образ? Не проще ли все делать одной-единственной операцией? Ответы на подобные вопросы дать тяжело, но, как правило, с опытом прихоидит понимание того, что подобная схема является одной из граней красоты Unix-систем.

Попробуем все-таки разобраться, почему в Unix-системах порождение процесса отделено от запуска программы. Для этого выясним, что же происходит с данными при "клонировании" процесса. Итак, каждый процесс хранит в своей памяти различные данные (переменные, файловые дескрипторы и проч.). При порождении нового процесса, потомок получает точную копию данных родителя. Но как только новый процесс создан, родитель и потомок уже распоряжаются своими копиями по своему усмотрению. Это позволяет распараллелить программу, заставив ее выполнять какой-нибудь трудоемкий алгоритм в отдельном процессе.

Может быть кто-то из вас слышал про то, что в Linux есть потоки, которые позволяют в одной программе реализовывать параллельное выполнение нескольких функций. Опять же возникает вопрос: "Если есть потоки, зачем вся эта головомойка с клонированиями и заменой образов?". А дело в том, что потоки работают с общими данными и выполняются в одной программе. Если в потоке произошло что-то страшное, то это, как правило, отражается на всей программе в целом. Хотя технически потоки реализованы в Linux на базе процессов, но процесс все же является более независимой единицей. Крах дочернего процесса никак не отражается на работе родителя, если сам родитель этого не пожелает.

По правде сказать, программисты редко прибегают к методике распараллеливания одной программы при помощи процессов. Но суть в том, что в Unix-системах программист обладает полной свободой выбора стратегии многозадачности. И это здорово!

Разберемся теперь с тем, как на практике происходит "клонирование" процессов. Для этого используется простой системный вызов fork(), прототип которого находится в файле unistd.h:


pid_t fork (void);

Если fork() завершается с ошибкой, то возвращается -1. Это редкий случай, связанный с нехваткой памяти или превышением лимита на количество процессов. Но если разделение произошло, то программе нужно позаботиться об идентификации своего "Я", то есть определении того, где родитель, а где потомок. Это делается очень просто: в родительский процесс fork() возвращает идентификатор потомка, а потомок получает 0. Следующий пример демонстрирует то, как это происходит.


/* fork01.c */
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>

int main (void)
{
        pid_t pid = fork ();

        if (pid == 0) {
                printf ("child (pid=%d)\n", getpid());
        } else {
                printf ("parent (pid=%d, child's pid=%d)\n", getpid(), pid);
        }

        return 0;
}

Проверяем, что получилось:


$ gcc -o fork01 fork01.c
$ ./fork01
child (pid=21026)
parent (pid=21025, child's pid=21026)

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

6.4. Замена образа процесса

Итак, теперь мы умеем порождать процессы. Научимся теперь заменять образ текущего процесса другой программой. Для этих целей используется системный вызов execve(), который объявлен в заголовочном файле unistd.h вот так:


int execve (const char * path, char const * argv[], char * const envp[]);

Все очень просто: системный вызов execve() заменяет текущий образ процесса программой из файла с именем path, набором аргументов argv и окружением envp. Здесь следует только учитывать, что path - это не просто имя программы, а путь к ней. Иными словами, чтобы запустить ls, нужно в первом аргументе указать "/bin/ls".

Массивы строк argv и envp обязательно должны заканчиваться элементом NULL. Кроме того, следует помнить, что первый элемент массива argv (argv[0]) - это имя программы или что-либо иное. Непосредственные аргументы программы отсчитываются от элемента с номером 1.

В случае успешного завершения execve() ничего не возвращает, поскольку новая программа получает полное и безвозвратное управление текущим процессом. Если произошла ошибка, то по традиции возвращается -1.

Рассмотрим теперь пример программы, которая заменяет свой образ другой программой.


/* execve01.c */
#include <unistd.h>
#include <stdio.h>

int main (void)
{
        printf ("pid=%d\n", getpid ());
        execve ("/bin/cat", NULL, NULL);

        return 0;
}

Итак, данная программа выводит свой PID и передает безвозвратное управление программе cat без аргументов и без окружения. Проверяем:


$ gcc -o execve01 execve01.c
$ ./execve01
pid=30150

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


$ ps -e | grep 30150
30150 pts/3    00:00:00 cat

Итак, мы убедились, что теперь процесс 30150 выполняет программа cat. Теперь можно вернуться в исходное окно и нажатием Ctrl+D завершить работу cat.

И, наконец, следующий пример демонстрирует запуск программы в отдельном процессе.


/* forkexec01.c */
#include <unistd.h>
#include <stdio.h>

extern char ** environ;

int main (void)
{
        char * echo_args[] = { "echo", "child", NULL };

        if (!fork ()) {
                execve ("/bin/echo", echo_args, environ);
                fprintf (stderr, "an error occured\n");
                return 1;
        }

        printf ("parent");
        return 0;
}

Проверяем:


$ gcc -o forkexec01 forkexec01.c
$ ./forkexec01
parent
child

Обратите внимание, что поскольку execve() не может возвращать ничего кроме -1, то для обработки возможной ошибки вовсе не обязательно создавать ветвление. Иными словами, если вызов execve() возвратил что-то, то это однозначно ошибка.


Copyright © 2003-2006, 2007 Nikolay N. Ivanov
Distributed under the GNU Free Documentaton License

Архив документации на OpenNet.ru