IPC - введение (от начинающего программера....)

Полезные советы и программы от пользователей нашего форума.

Модератор: Модераторы разделов

ZaP
Сообщения: 10

IPC - введение

Сообщение ZaP »

Linux IPC(Interprocess communications) представляет межпроцессорные
коммуникации в Линукс. При помощи них строется общение процессов по
принцыпу клиент/сервер.
Зачем они нужны? И для чего их использовать?
Конечно каждый может поразному их использовать.Для некоторых это
облегчает программирование и уменшает объем кода при помощи
использования стандартных команд в Линуксе или других никс систем.
Действительно зачем писать улучшенную сортировку(QuickSort,HeapSort,
RadixSort) мучится в их отладке если это можно поручить процессору
"sort" который за нас это очень даже хорошо сделает.Другие, кто
программирует под Линукс очень долго и пишит очень сложные вещи,
будет использовать для связки разных программ.

Это статья будет вводная в цикл статей про межпроцессорные коммуникации
в Линукс.

Для начала ознакомимся с самым понятием процесса.

1 Что такое процесс и счем его едят???

Процессов на компах выполняется очень много, так много что сложно
представить себе сколько их на самом деле(это возможно но лучше
ненадо =)). Самые простые "видимые процессы" это твой аудио плеер,
твой мыллер,твой браузер в котором загружена эта статья
с сам знаешь кокого сайта =).Это лишь самая видимая часть процессов и она
полностью не расскрывает понятие процессов в полном объеме.
Для более полного расскрытия понятия процессора введем такие
определения:
КОД - набор инструкция изкоторых состоит программа.

ОБЛАСТЬ ПАМЯТИ - часть машинной памяти, занятая данными
программы.

СОСТОЯНИЕ ПРОЦЕССОРА - значения параметра микропроцессора
такие как флаги или счетчик комманд.

Припомощи этих определение можно дать определение выполняющейся программе:
ВЫПОЛНЯЮЩЕЕСЯ ПРОГРАММА - совокупность КОДА, ОБЛАСТИ ПАМЯТИ,
СОСТОЯНИЯ ПРОЦЕССОРА.

А ВЫПОЛНЯЮЩЕЕСЯ ПРОГРАММА тоже самое что и ЗАДАЧА и ПРОЦЕСС.
или если говорить более конкретно то: процесс-это совокупность кода,
области памяти и состояния процесса.

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

2 Процессы в Линук и Юникс

Каждый из нас много раз проссматривал какие процессы выполняются
на своей машине при помощи команды "ps". "ps" - сокращение от фразы:
"process status" (что в переводе на русский язык означает "состояния
процесса") и эта команда будет выдовать примерно такой текст:

[ZaP@aibulat Process]$ ps
PID TTY TIME CMD
14009 pts/1 00:00:00 bash
14095 pts/1 00:00:00 ps
[ZaP@aibulat Process]$

Рассмотрим значения некоторых полей в этой таблице:
PID - Process ID(Идентифицирующий номер процессора)
TTY - На какой консоли выполняется этот процесс
CMD - Название процесса.
Здесь мы не рассмотрели колонку под названием "TIME" так как
она для нас сейчас не играет особой роли.
Насчет определьния процесса еще хочется отметить пару пораметров процессора:
UID - User ID(Идентифицирующий номер владельца процесса)
PPID - Parent Process ID(Идентифицирующий номур родительского
процесса).

3 Жизненный цикл процесса

Процесс init - прародитель всех процессов. Все процессы кроме
init порождаются командой "fork()" кроме процесса init(он порождается
во время загрузки). Fork с английского означает ветвление, для процессов
это означает, что каждый процесс порождыется от другого процесса по этому
все процессы кроме init имеют родителей. И поэтому можно представить что
процесс init - это корень а дальше от него отходят ветки для наглядности
можно привести пример:
__________________________________________________________________________

init - корень дерева
/ | \
/ \ \
My_prog bash ps - его ветви
/ \
/ \
My_Prog .... - ветви от процесса My_Prog
___________________________________________________________________________

Синтаксис функции "fork" достаточно прост:
pid_t fork(void);
Форк возращает PID дочернего, если процесс дочерний создался, и 0, если это
пытается сделать дочерний процесс.Причем fork порождает процесс идентичный
родительскому процессу С таким же КОДОМ,СОСТОЯНИЕМ ПРОЦЕССОРА и такойже
МАШИННОЙ памятью, Но участок кода, который выполняется у дочернего процесса
может быть другим чем у родительского процесса для того чтобы дочерний
и родительский процесс проходили разные участки кода используется простая
схема:
_____________________________________________________________________________
...

int main(){
pid_t pid;
if((pid=fork())==0){
/*Здесь код дочернего процесса*/
return 0;
}
/*Здесь код родительского процесса*/
return 0;
}

...
_____________________________________________________________________________

Имею это схему можно написать простой пример много задачного кода который
будет выводить какой пример сейчас выполняется родительский или дочерний:
_____________________________________________________________________________
/*demo_fork.c*/
#include<stdio.h>
#include<sys/types.h>
#include<unistd.h>

int main(){
pid_t pid;
int i;

/*Попытка создание дочернего процесса*/
if((pid=fork())==0){
/*Код дочернего процесса*/
for(i=0;i<8;i++)printf("-ДОЧЕРНИЙ-\n");
return 0;
}
/*Код родительского процесса*/
for(i=0;i<8;i++)printf("+РОДИТЕЛЬСКИЙ+\n");
return 0;
};
_____________________________________________________________________________

Пир выполнении эта программа скорее все выдаст примерно такое расспололжение:

[ZaP@aibulat Process]$ ./demo_fork
-ДОЧЕРНИЙ-
-ДОЧЕРНИЙ-
-ДОЧЕРНИЙ-
-ДОЧЕРНИЙ-
-ДОЧЕРНИЙ-
-ДОЧЕРНИЙ-
-ДОЧЕРНИЙ-
-ДОЧЕРНИЙ-
+РОДИТЕЛЬСКИЙ+
+РОДИТЕЛЬСКИЙ+
+РОДИТЕЛЬСКИЙ+
+РОДИТЕЛЬСКИЙ+
+РОДИТЕЛЬСКИЙ+
+РОДИТЕЛЬСКИЙ+
+РОДИТЕЛЬСКИЙ+
+РОДИТЕЛЬСКИЙ+
[ZaP@aibulat Process]$

или наоборот:

[ZaP@aibulat Process]$ ./demo_fork
+РОДИТЕЛЬСКИЙ+
+РОДИТЕЛЬСКИЙ+
+РОДИТЕЛЬСКИЙ+
+РОДИТЕЛЬСКИЙ+
+РОДИТЕЛЬСКИЙ+
+РОДИТЕЛЬСКИЙ+
+РОДИТЕЛЬСКИЙ+
+РОДИТЕЛЬСКИЙ+
-ДОЧЕРНИЙ-
-ДОЧЕРНИЙ-
-ДОЧЕРНИЙ-
-ДОЧЕРНИЙ-
-ДОЧЕРНИЙ-
-ДОЧЕРНИЙ-
-ДОЧЕРНИЙ-
-ДОЧЕРНИЙ-
[ZaP@aibulat Process]$

Вы можете сказать что это противоречит условию многозадачности т.к вы вывилось по
очереди, Да они вывелись все поочереди но только из-за того что printf быстро все
выводит на экран то есть за время меньшее одного кванта. Но что же сделать для
того чтобы пример этот выглядел более наглядно перед выводом(printf) поставим
функцию задержки:
sleep(rand()%4);
Причем это задержка будет случайная от 0 до 3 секунд.
что покажет что процессы выполняются поочереди:

[ZaP@aibulat Process]$ ./demo_fork2
+РОДИТЕЛЬСКИЙ+
-ДОЧЕРНИЙ-
+РОДИТЕЛЬСКИЙ+
-ДОЧЕРНИЙ-
+РОДИТЕЛЬСКИЙ+
-ДОЧЕРНИЙ-
+РОДИТЕЛЬСКИЙ+
-ДОЧЕРНИЙ-
+РОДИТЕЛЬСКИЙ+
-ДОЧЕРНИЙ-
+РОДИТЕЛЬСКИЙ+
-ДОЧЕРНИЙ-
+РОДИТЕЛЬСКИЙ+
+РОДИТЕЛЬСКИЙ+
-ДОЧЕРНИЙ-
-ДОЧЕРНИЙ-
[ZaP@aibulat Process]$

Ни чего страшного не произойдет если он выведет по другому это зависит
только от того какая будет задержка,а она будет разная, так как мы используем функцию
"rand()".
Но иногда нам надо дождаться выполнения выполнения дочернего процесса а потом приступить
к выполнению родительского кода. Для этого используется функция "waitpid()", Синтаксис
этой функции такой:

pid_t waitpid(pid_t PID,int *STATUS_PTR,int OPTIONS);

PID - PID ожидаймого процесса
STATUST_PTR - указатель на целое число которое будет содержать статус дочернего
процесса(NULL - если информация не нужна).
OPTIONS - Опции которые можно передовать процессу, но это параметр сейчас не
интересует.

Для наглядного примера напишем программу которая будет архивировать текстовый файл и
копировать в папку "/tmp/archives/". Сначала для этого в директории "/tmp"
создадим папку "archives" командой "mkdir":

[ZaP@aibulat tmp]$ mkdir archives

Теперь перейдем к написанию программы.

!ПРИМЕЧАНИЕ программа не обезательно должна лежать в папке /tmp/archives. Она может
лежать в любом месте хоть в корневом каталоге(но лучше ей там не лежать =)).
_____________________________________________________________________________

/*archiv_cp.c*/
#include<stdio.h>
#include<string.h>
#include<sys/types.h>
#include<sys/wait.h>
#include<unistd.h>

#define COPPY_DIRECTORY "/tmp/archives/"

int main(int argc,char *argv[]){
pid_t pid;
pid_t mypid;
int status;
if(argc!=2){
printf("USAGE:archiv_cpp [filename]\n");
return -1;
}
if((pid=fork())==0){
mypid=getpid();
printf("Дочерний процесс %d приступил к выполнению\n",mypid);
printf("Начинаю архивировать файл: %s..........\n",argv[1]);
sleep(rand()%4);
execl("/bin/gzip","gzip",argv[1],0);
return 0;
}
mypid=getpid();
printf("Родительский процесс %d ждет выполнения дочернего процесса %d\n",mypid,pid);
waitpid(pid,NULL,0);
printf("Дочерений процесс %d смог за архивировать файл %s\n",pid,argv[1]);
printf("Копирую файл %s.gz........\n",argv[1]);
execl("/bin/cp","cp",strcat(argv[1],".gz"),COPPY_DIRECTORY,0);
return 0;

};
_____________________________________________________________________________

В этой программе использовались только 2 незнакомые нам функция "execl()",
которая выводит посылает команды на выполнение процессором, и "getpid",
которая возращает PID процесса, который послал этот запрос .

4.Итог
В этой теме была рассказано про понятие процессов создание их и про из
свойство. Тут не была рассмотрена структура процесса в ядре Линукса так
как автор считает что это для начального этапа не нужно.
Надеюсь читатель этой статьи не будет бить меня палками за то, что
я испольовал некоторые примеры взятые с
http://www.linuxfocus.org/Russian/November...rticle272.shtml

КоНеЦ статьи но НаЧаЛо цикла статей посвещенной межпроцессорной коммуникации
в линуксе =)

З.Ы. Не смотрите но громадное количество ошибок(уменя их всегда так маного =))
З.Ы.Ы
Если вам понравилась статья и вам ещё хочется узнать про программирование межпроцессорных коммуникаций мыльте мне zap@land.ru.
З.Ы.Ы.Ы
Эта же статья будет опубликована на lug.bash.ru
Спасибо сказали:

Аватара пользователя
t.t
Бывший модератор
Сообщения: 7390
Статус: думающий о вечном
ОС: Debian, LMDE

Re: IPC - введение

Сообщение t.t »

(ZaP @ Воскресенье, 14 Ноября 2004, 16:59) писал(а):Linux IPC(Interprocess communications) представляет межпроцессорные коммуникации в Линукс.
Хороший материал. Одно замечание: не "межпроцессорные" -- "межпроцессовые".

P.S. Кстати, alv вроде хотел на сайте и по программированию статьи размещать. У него, правда, с хостингом сейчас проблемы; но когда решится, обратитесь?
¡иɯʎdʞ ин ʞɐʞ 'ɐнɔɐdʞǝdu qнεиж
Спасибо сказали:

ZaP
Сообщения: 10

Re: IPC - введение

Сообщение ZaP »

(t.t @ Понедельник, 15 Ноября 2004, 14:37) писал(а):
(ZaP @ Воскресенье, 14 Ноября 2004, 16:59) писал(а):Linux IPC(Interprocess communications) представляет межпроцессорные коммуникации в Линукс.
Хороший материал. Одно замечание: не "межпроцессорные" -- "межпроцессовые".

P.S. Кстати, alv вроде хотел на сайте и по программированию статьи размещать. У него, правда, с хостингом сейчас проблемы; но когда решится, обратитесь?


Ошибку учту =))))
Как проблемы исчезнут мыль обязательно пришлю ;)
Спасибо сказали:

MedVed
Сообщения: 112

Re: IPC - введение

Сообщение MedVed »

К вопросу о межпроцессовом взаимодействии. Есть хорошая книга для ознакомления. Выходные данные:
Библиотека программиста на рабочей станции. UNIX, X Window, Motif. / А.В. Доценко, А.Б. Исаков, А.Ю. Рябов; Под редакцией А.Ю Рябова – М.: Аналитик, 1994.
Рассматривается все возможные способы: сигналы, сообщения, конвейеры, очереди сообщений, разделяемые файлы, разделяемая память. Если найду электронный вариант - скину сюда же.
МСВС 3.0/Linux Mandrake 8.0
Спасибо сказали:

Аватара пользователя
Sparky
Сообщения: 604
Статус: core dumped
ОС: Plan 9

Re: IPC - введение

Сообщение Sparky »

Да, не понятно зачеи писать о том, о чем уже не раз написано причем наверняка более компетентно?
Блог
--------------------

GCS/M/MU/P/IT/E d- s: a- C++(+++) UBL++ P->-- L+++$ E- W+++$ N* o? K? w>--
O M-@ V- PS@ PE+ Y+ PGP+ t 5 X R* tv-->- b++ DI? D>+ G e+(++) h--- r+ y++
Спасибо сказали:

MedVed
Сообщения: 112

Re: IPC - введение

Сообщение MedVed »

А вот и электронная версия книги. Надеюсь она сюда запихнется. :)
МСВС 3.0/Linux Mandrake 8.0
Спасибо сказали:

nnivanov
Сообщения: 8

Re: IPC - введение

Сообщение nnivanov »

Книг и статей по многозадачности в Linux/Unix много, а все они пересказывают одно и то же (не в обиду автору). А вот кто-нибудь знает, зачем функции fork() требуется порождать идентичный процесс и почему ее вообще не объединяют воедино с функциеями из семейства exec() (дурной пример system() я не считаю)?

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