Proseslər arası əlaqə
§4 Proseslərarası əlaqə
Bu mövzuda Unix-də eyni kompüterdə icra olunan iki proses arasında məlumat mübadiləsi məsələləri ilə məşğul olacağıq.
Unix-də eyni kompüterdə icra olunan proseslər arasında məlumat mübadiləsi üçün proqram kanalları, adlandırılmış proqram kanalları və paylanmış yaddaş vasitələrindən istifadə edirlər.
4.1 Proqram kanalları
Proqram kanalları eyni kompüterdə icra olunan proqramlar arasında məlumat ötürülməsini həyata keçirmək üçün istifadə olunur.
Proqram kanallarının istifadəsinə aid nümunəyə baxaq. Yuxarıdakı mövzularda ps əmri ilə tanış olmuşduq. Qeyd etdik ki, -e seçimi ilə verildikdə, ps əmri hal-hazırda kompüterdə icra olunan proqramlar barəsində məlumat çap edir.
Unix-də tez-tez istifadə olunan digər faydalı əmr isə, grepəmridir. grep əmrinin sintaksisi aşağıdakı kimidir: grep axtarılan_ifadə fayl. grep əmri verilmiş faylı axtarır və özündə axtarılan_ifadə saxlayan sətirləri çap edir. Misal üçün, tutaq ki, özündə aşağıdakı sətirləri saxlayan sheherler adli fayl verilmişdir:
bakı azərbaycan
istanbul türkiyə
london britaniya
sumqayıt azərbaycan
moskva rusiya
gəncə azərbaycan
cat əmri ilə onda olan məlumatları çap edək:
[ferid@fedora progs]$
[ferid@fedora progs]$ cat sheherler
bakı azərbaycan
istanbul türkiyə
london britaniya
sumqayıt azərbaycan
moskva rusiya
gəncə azərbaycan
[ferid@fedora progs]$
[ferid@fedora progs]$
İndi əgər bu faylda özündə "azərbaycan" sözünü saxlayan sətirləri çap etmək istəsək, grep azərbaycan sheherler əmrini daxil etməliyik:
[ferid@fedora progs]$
[ferid@fedora progs]$ grep azərbaycan sheherler
bakı azərbaycan
sumqayıt azərbaycan
gəncə azərbaycan
[ferid@fedora progs]$
[ferid@fedora progs]$
Əgər grep moskva sheherler əmrini daxil etsəydik, onda moskva rusiya sətri çap olunardı:
[ferid@fedora progs]$
[ferid@fedora progs]$ grep moskva sheherler
moskva rusiya
[ferid@fedora progs]$
[ferid@fedora progs]$
İndi isə, ps və grep əmrlərindən istifadə etməklə, hal-hazırda icra olunan proseslər arasında adında x simvolu olanlarını çap edək. Bunun üçün, ps -e əmrinin nəticəsini grep əmrinə yönləndirməliyik və axtarış parametri olaraq x daxil etməliyik. Unix-də bir proqramın nəticəsini digər proqrama yönləndirmək üçün proqram kanallarından istifadə olunur. Proqram kanalı | simvolu ilə işarə edilir. Proqram kanalı vasitəsilə, zəncirvari olaraq bir neçə proqramın nəticəsini birindən digərinə ötürə bilərik. Terminaldan aşağıdakı əmri daxil edək: ps -e | grep x
[ferid@fedora progs]$
[ferid@fedora progs]$ ps -e | grep x
421 ? 00:00:00 ext4-dio-unwrit
899 ? 00:00:00 ext4-dio-unwrit
958 ? 00:00:00 ext4-dio-unwrit
1331 ? 00:00:00 xinetd
4746 ? 00:00:15 VirtualBox
4761 ? 00:00:04 VBoxXPCOMIPCD
4766 ? 00:00:14 VBoxSVC
12768 ? 00:00:00 chrome-sandbox <defunct>
[ferid@fedora progs]$
[ferid@fedora progs]$
Gördüyümüz kimi, bu zaman ps -e əmrinin yalnız özündə x simvolu saxlayan sətirləri çap olundu. Proses aşağıdakı kimi baş verir. Əvvəlcə ps -e əmrinin nəticəsi proqram kanalı vasitəsilə grep əmrinə ötürülür. Daha sonra, grep əmri bu nəticədən özündə x simvolu saxlayan sətirləri çap edir.
İndi isə, gəlin, Unix-də proqram kanallarının nə cür yaradılması ilə tanış olaq.
Unix-də proqram kanalı yaratmaq üçün (qısa olaraq kanal) pipe sistem çağrısından istifadə olunur. Funksiyanın elanı aşağıdakı kimidir:
int pipe(int *);
pipe funksiyası unistd.h başlıq faylında təyin edilmişdir. pipe funksiyası arqument olaraq int tipindən olan 2 elementdən ibarət cərgə gəbul edir. Əgər kanal yaratmaq uğurlu olarsa, onda pipe funksiyası həmin cərgənin elementlərindən kanal oxumaq və yazmaq üçün fayl əlaqələndiriciləri yaradır və nəticə olaraq, 0qiymətini qaytarır, əks halda, -1 qiymətini qaytarır. Proqram kanalı yaratmaq üçün sadə nümunə aşağıdakı kimi olar:
int fd[2];
pipe(fd);
Nəticədə proqram kanalı yaranmış olur. Proqram kanallarının iki başlığı olur, məlumat yazılan və məlumat oxunan başlıq.
Proqram kanalı yaratdıqdan sonra, fd[1] başlığına yazdığımız məlumatı fd[0] başlığından oxuya bilərik. Proqram nümunəsinə baxaq:
/* prg_4_1.c */
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
int main(){
char buf[20]={'0'};
int fd[2];
/* kanal yaradırıq */
if (pipe(fd)!=0)
{ printf("Proqram kanalı yaradıla bilmir \n");
exit(0);}
/* fd[1]-ə hər hansı məlumat yazırıq */
write(fd[1],"Salam", 5);
/* fd[0]-dan fd[1]-ə yazdığımız məlumati oxuyaq */
read(fd[0],buf,5);
/* buferə oxuduğumuz məlumatı ekranda çap edək */
printf("Kanaldan oxuduq %s\n",buf);
return 0;
}
Proqramı icra etsək:
[ferid@fedora progs]$
[ferid@fedora progs]$ gcc prg_4_1.c -o prg_4_1
[ferid@fedora progs]$
[ferid@fedora progs]$ ./prg_4_1
Kanaldan oxuduq Salam
[ferid@fedora progs]$
[ferid@fedora progs]$
Proqramın izahı:
Biz int tipli 2 elementdən ibarət fd cərgəsi elan edirik. Daha sonra, bu cərgəni pipe funksiyasına parametr kimi ötürürük. pipefunksiyası proqram kanalının yaradılması ilə nüvəyə müraciət edir. Nüvə proqram kanalını yaradır və onun uclarını fd cərgəsinin elementlərinə pərçimləyir. Bundan sonra, write əmri ilə fd[1] başlığına yazdığımız məlumatı, read əmri ilə fd[0] başlığından oxuya bilərik. Bu lokal bir kanalı xatırladır, hansı ki, eyni proqramın daxilində kanalın bir başından yazdığımız məlumatı digər başından oxuduq.
Proqram kanallarının əsas təyinatı isə, iki müxtəlif proqramı bir-biri ilə əlaqələndirməkdir. Belə ki, proqramlardan biri kanalın bir başına yazdığı məlumatı, digər proqram kanalın o biri başlığından oxuyur. Proqram nümunəsi:
/* prg_4_2.c */
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
int main(){
char buf[20]={'0'};
int fd[2];
/* kanal yaradırıq */
if (pipe(fd)!=0)
{ printf("Proqram kanalı yaradıla bilmir \n");
exit(0);}
/* yeni proses yaradırıq */
if (fork()==0){
/* oğul proses */
/* oğul kanala yazır */
write(fd[1],"Salam", 5);
return 0;
}
else{
/* ata proses */
/* ata oğulun göndərdiyi məlumatı oxuyur */
read(fd[0],buf,5);
printf("Oğul göndərdi %s\n",buf);
return 0;
}
}
Proqramı icra etsək:
[ferid@fedora progs]$
[ferid@fedora progs]$ gcc prg_4_2.c -o prg_4_2
[ferid@fedora progs]$
[ferid@fedora progs]$ ./prg_4_2
Oğul göndərdi Salam
[ferid@fedora progs]$
[ferid@fedora progs]$
Baxdığımız bu nümunə sadəcə göstəriş xarakterli nümunə idi, oğul və ata prosesləri arasında proqram kanalından istifadəni nümayiş etdirirdi. İndi isə, bir qədər maraqlı məsələlər ilə məşğul olaq. Yeni yaratdığımız oğul prosesə hər hansı proqram yükləyək, həmin proqramı icra edək və nəticəsini "ata"ya ötürək. Eyni zamanda ata prosesə də başqa bir proqram yükləyək və "oğul"un nətisəsini həmin proqrama verək. Aşağıdakı proqram nümunəsində biz bayaq yuxarıda göstərdiyimiz ps -e | grep x əmrini yerinə yetirəcəyik. Oğul prosesin yaddaş sahəsinə ps -e əmrini yükləyəcəyik. Oğul proses ps -e əmrini icra edəcək və nəticəni kanala yazacaq. Ata prosesin yaddaş sahəsinə isə, grep x əmrini yükləyəcəyik. Ata proses kanaldan oğul prosesinin göndərdiyi məlumatı oxuyub (ps -e əmrinin nəticəsi) grep-ə ötürəcək. Proqram nümunəsi aşağıdakı kimi olar:
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
int main(){
char buf[1024]={'0'};
int fd[2];
/* kanal yaradırıq */
if (pipe(fd)!=0)
{ printf("Proqram kanalı yaradıla bilmir \n");
exit(0);}
/* yeni proses yaradırıq */
if (fork()==0){
/* oğul proses */
/* oğul prosesə ps -e əmrini yükləyirik */
char *argv[3];
argv[0]=malloc(8);
strcpy(argv[0],"/bin/ps\0");
argv[1] = malloc(3);
strcpy(argv[1],"-e\0");
argv[2] = NULL;
/* standart çıxış başlığını 1, fd[1] ilə əvəz edirik */
close(fd[0]);
close(1);
dup(fd[1]);
execve("/bin/ps",argv,NULL);
}
else{
/* ata proses */
/* ata prosesə grep x əmrini yükləyirik */
char *argv[3];
argv[0]=malloc(10);
strcpy(argv[0],"/bin/grep\0");
argv[1] = malloc(2);
strcpy(argv[1],"x\0");
argv[2] = NULL;
close(fd[1]);
close(0);
dup(fd[0]);
execve("/bin/grep",argv,NULL);
}
}
Proqramı icra edək:
oğul[ferid@fedora progs]$ oğul
oğul[ferid@fedora progs]$ gcc prg_4_3.c -o prg_4_3oğul
oğul[ferid@fedora progs]$ oğul
oğul[ferid@fedora progs]$ ./prg_4_3oğul
oğul400 ? 00:00:00 ext4-dio-unwritoğul
oğul858 ? 00:00:00 ext4-dio-unwritoğul
oğul918 ? 00:00:00 ext4-dio-unwritoğul
oğul1352 ? 00:00:00 xinetdoğul
oğul3519 ? 00:00:10 VirtualBoxoğul
oğul3534 ? 00:00:08 VBoxXPCOMIPCDoğul
oğul3539 ? 00:00:24 VBoxSVCoğul
oğul4642 ? 00:00:00 chrome-sandbox <defunct>oğul
oğul23337 ? 00:11:55 VirtualBoxoğul
oğul[ferid@fedora progs]$oğul
oğul[ferid@fedora progs]$oğul