- ЋЎй п (б®ў¬Ґбв® ЁбЇ®«м§гҐ¬ п) Ї ¬пвм
- Ѓлбв஥ «®Є «м®Ґ ў§ Ё¬®¤Ґ©бвўЁҐ
- Њ®¤Ґ«м Ї ¬пвЁ
- ‚뤥«ҐЁҐ
- Џ®¤Є«о票Ґ Ё ®вЄ«о票Ґ
- “Їа ў«ҐЁҐ Ё ®бў®Ў®¦¤ҐЁҐ ®ЎйҐ© Ї ¬пвЁ
- ЏаЁ¬Ґа Їа®Ја ¬¬л
- ‡ Ё Їа®вЁў
- Знакомство с межпроцессным взаимодействием на Linux
- Именованный канал
- Пример
- Разделяемая память
- Пример
- Семафор
- Семафор со счетчиком
- Пример семафора со счетчиком
- Бинарный семафор
- Пример mutex
- Вместо заключения
ЋЎй п (б®ў¬Ґбв® ЁбЇ®«м§гҐ¬ п) Ї ¬пвм
Ћ¤Ё Ё§ б ¬ле Їа®бвле ¬Ґв®¤®ў ¬Ґ¦Їа®жҐбб®ў®Ј® ў§ Ё¬®¤Ґ©бвўЁп — ЁбЇ®«м§®ў вм ®Ўйго Ї ¬пвм. ЋЎй п Ї ¬пвм Ї®§ў®«пҐв ¤ўг¬ Ё«Ё Ў®«ҐҐ Їа®жҐбб ¬ ®Ўа й вмбп Є ®¤®© Ё в®© ¦Ґ ®Ў« бвЁ Ї ¬пвЁ, Є Є Ўг¤в® ®Ё ўбҐ ўл§лў «Ё malloc Ё Ё¬ Ўл«Ё ў®§ўа йҐл гЄ § ⥫Ё ®¤г Ё вг ¦Ґ дЁ§ЁзҐбЄго Ї ¬пвм. Љ®Ј¤ ®¤Ё Їа®жҐбб Ё§¬ҐпҐв Ї ¬пвм, ўбҐ ¤агЈЁҐ Їа®жҐббл «ўЁ¤пв» ¬®¤ЁдЁЄ жЁо.
Ѓлбв஥ «®Є «м®Ґ ў§ Ё¬®¤Ґ©бвўЁҐ
ЋЎй п Ї ¬пвм — б ¬ п Ўлбва п д®а¬ ¬Ґ¦Їа®жҐбб®ў®Ј® ў§ Ё¬®¤Ґ©бвўЁп, Ї®в®¬г зв® ўбҐ Їа®жҐббл б®ў¬Ґбв® ЁбЇ®«м§гов ®¤г Ёвг ¦Ґ з бвм Ї ¬пвЁ. „®бвгЇ Є нв®© ®ЎйҐ© Ї ¬пвЁ ®бгйҐбвў«пҐвбп б в®© ¦Ґ бЄ®а®бвмо, зв® Ё ЇаЁ ®Ўа 饨Ё Є Ґб®ў¬Ґбв® ЁбЇ®«м§гҐ¬®© Ї ¬пвЁ, Ё нв® Ґ вॡгҐв бЁб⥬®Ј® ўл§®ў Ё«Ё ўе®¤ ў п¤а®. ќв® в Є¦Ґ Ґ вॡгҐв Ё§«ЁиҐЈ® Є®ЇЁа®ў Ёп ¤ ле.
Џ®бЄ®«мЄг п¤а® Ґ бЁеа®Ё§ЁагҐв ¤®бвгЇл Є б®ў¬Ґбв® ЁбЇ®«м§гҐ¬®© Ї ¬пвЁ, ўл ¤®«¦л б ¬Ё ®ЎҐбЇҐзЁвм бЁеа®Ё§ жЁо. Ќ ЇаЁ¬Ґа, Їа®жҐбб Ґ ¤®«¦Ґ зЁв вм Ё§ Ї ¬пвЁ, Ї®Є ¤ лҐ Ґ § ЇЁб л вг¤ , Ё ¤ў Їа®жҐбб Ґ ¤®«¦л ЇЁб вм Ї® ®¤®¬г Ё ⮬㠦Ґ ¤аҐбг Ї ¬пвЁ ў ®¤® Ё в® ¦Ґ ўаҐ¬п. ЋЎй п бва ⥣Ёп Ё§ЎҐ¦ Ёп гб«®ўЁ© Ј®ЄЁ б®бв®Ёв ў ⮬, зв®Ўл ЁбЇ®«м§®ў вм ᥬ д®ал.
Њ®¤Ґ«м Ї ¬пвЁ
—в®Ўл ЁбЇ®«м§®ў вм ᥣ¬Ґв ®ЎйҐ© Ї ¬пвЁ, ®¤Ё Їа®жҐбб ¤®«¦Ґ ўл¤Ґ«Ёвм ᥣ¬Ґв. ’®Ј¤ Є ¦¤л© Їа®жҐбб, ¦Ґ« ойЁ© ®Ўа й вмбп Є ᥣ¬Ґвг ¤®«¦Ґ Ї®¤Є«озЁвм ᥣ¬Ґв. Џ®б«Ґ ®Є®з Ёп ҐЈ® ЁбЇ®«м§®ў Ёп ᥣ¬Ґв , Є ¦¤л© Їа®жҐбб ®вЄ«оз Ґв ᥣ¬Ґв. ‚ ҐЄ®в®ал© ¬®¬Ґв, ®¤Ё Їа®жҐбб ¤®«¦Ґ ®бў®Ў®¤Ёвм ᥣ¬Ґв.
Џ®Ё¬ ЁҐ ¬®¤Ґ«Ё Ї ¬пвЁ Linux Ї®¬®Ј Ґв ®ЎкпбЁвм Їа®жҐбб ўл¤Ґ«ҐЁп Ё Ї®¤Є«о票п. Џ®¤ Linux , ўЁавг «м п Ї ¬пвм Є ¦¤®Ј® Їа®жҐбб а §ЎЁв бва Ёжл. Љ ¦¤л© Їа®жҐбб Ї®¤¤Ґа¦Ёў Ґв ®в®Ўа ¦ҐЁҐ ҐЈ® ¤аҐб®ў Ї ¬пвЁ нвЁ бва Ёжл ўЁавг «м®© Ї ¬пвЁ, Є®в®алҐ б®¤Ґа¦ в д ЄвЁзҐбЄЁҐ ¤ лҐ. € е®вп Є ¦¤л© Їа®жҐбб Ё¬ҐҐв б®ЎбвўҐлҐ ¤аҐб , ®в®Ўа ¦ҐЁп ¬®ЈЁе Їа®жҐбб®ў ¬®Јгв гЄ §лў вм ®¤г Ё вг ¦Ґ бва Ёжг, а §аҐи п б®ў¬Ґб⮥ ЁбЇ®«м§®ў ЁҐ Ї ¬пвЁ.
‚뤥«ҐЁҐ ®ў®Ј® ᥣ¬Ґв ®ЎйҐ© Ї ¬пвЁ ЇаЁў®¤Ёв Є б®§¤ Ёо бва Ёжл ўЁавг «м®© Ї ¬пвЁ. Џ®бЄ®«мЄг ўбҐ Їа®жҐббл ¦Ґ« ов ®Ўа вЁвмбп Є ®¤®¬г Ё ⮬㠦Ґ ®ЎйҐ¬г ᥣ¬Ґвг, в® в®«мЄ® ®¤Ё Їа®жҐбб ¤®«¦Ґ ўл¤Ґ«Ёвм ®ўл© ®ЎйЁ© ᥣ¬Ґв. ‚뤥«ҐЁҐ бгйҐбвўго饣® ᥣ¬Ґв Ґ б®§¤ Ґв ®ўле бва Ёж, ў®§ўа й Ґв Ё¤ҐвЁдЁЄ в®а ¤«п бгйҐбвўгойЁе. —в®Ўл а §аҐиЁвм Їа®жҐббг ЁбЇ®«м§®ў вм ᥣ¬Ґв ®ЎйҐ© Ї ¬пвЁ, Їа®жҐбб Ї®¤Є«оз Ґв ᥣ¬Ґв, Є®в®ал© ¤®Ў ў«пҐв ®в®Ўа ¦ҐЁҐ ҐЈ® ўЁавг «м®© Ї ¬пвЁ ®ЎйҐ¤®бвгЇлҐ бва Ёжл ᥣ¬Ґв . Љ®Ј¤ а Ў®в б ᥣ¬Ґв®¬ § ўҐаиҐ , нвЁ ®в®Ўа ¦ҐЁп г¤ «повбп. Љ®Ј¤ Ё ®¤Ё Ё§ Їа®жҐбб®ў Ґ е®зҐв ®Ўа й вмбп Є ᥣ¬Ґв ¬ ®ЎйҐ© Ї ¬пвЁ, Є Є®©-в® ®¤Ё Їа®жҐбб ¤®«¦Ґ ®бў®Ў®¤Ёвм бва Ёжл ўЁавг «м®© Ї ¬пвЁ. ‚ᥠᥣ¬Ґвл ®ЎйҐ© Ї ¬пвЁ ўл¤Ґ«повбп Ї®бва Ёз® Ё ®ЄагЈ«повбп ¤® а §¬Ґа бва Ёжл бЁб⥬л, Є®в®ал© пў«пҐвбп зЁб«®¬ Ў ©в®ў ў бва ЁжҐ Ї ¬пвЁ. Ќ бЁб⥬ е Linux , а §¬Ґа бва Ёжл а ўҐ 4 ЉЃ, ® ўл ¤®«¦л Ї®«гзЁвм нв® § 票Ґ, ўл§лў п дгЄжЁо getpagesize .
‚뤥«ҐЁҐ
Џа®жҐбб ўл¤Ґ«пҐв ᥣ¬Ґв ®ЎйҐ© Ї ¬пвЁ, ЁбЇ®«м§гп shmget (» SHared Memory GET «). …Ј® ЇҐаўл© Ї а ¬Ґва — 楫®зЁб«Ґл© Є«оз, Є®в®ал© ®ЇаҐ¤Ґ«пҐв, Є Є®© ᥣ¬Ґв б®§¤ вм. ЌҐбўп§ лҐ Їа®жҐббл ¬®Јгв ®Ўа й вмбп Є ®¤®¬г Ё ⮬㠦Ґ ᥣ¬Ґвг, ЁбЇ®«м§гп ®¤® Ё в® ¦Ґ Є«о祢®Ґ § 票Ґ. Љ ᮦ «ҐЁо, ¤агЈЁҐ Їа®жҐббл, ў®§¬®¦®, в Є¦Ґ ўлЎа «Ё в®в ¦Ґ б ¬л© Є«оз, зв® ¬®¦Ґв ЇаЁўҐбвЁ Є Є®д«ЁЄвг. €бЇ®«м§гп бЇҐжЁ «мго Є®бв вг IPC_PRIVATE Є Є Є«о祢®Ґ § 票Ґ, Ј а вЁагҐвбп, зв® б®§¤ бвбп б®ўҐа襮 ®ўл© ᥣ¬Ґв Ї ¬пвЁ.
…Ј® ўв®а®© Ї а ¬Ґва ®ЇаҐ¤Ґ«пҐв зЁб«® Ў ©в®ў ў ᥣ¬ҐвҐ. Џ®бЄ®«мЄг ᥣ¬Ґвл ўл¤Ґ«повбп Ї®бва Ёз®, зЁб«® д ЄвЁзҐбЄЁ ўл¤Ґ«Ґле Ў ©в ®ЄагЈ«пҐвбп ¤® а §¬Ґа бва Ёжл.
’аҐвЁ© Ї а ¬Ґва — Ї®а §а冷Ґ ¤ў®Ёз®Ґ Ё«Ё § 票© д« ¦Є , Є®в®алҐ ®ЇаҐ¤Ґ«пов ®ЇжЁЁ Є shmget . ‡ 票п д« ¦Є ўЄ«оз ов в ЄЁҐ Ї а ¬Ґвал:
- IPC_CREAT — нв®в д« ¦®Є гЄ §лў Ґв, зв® ¤®«¦Ґ Ўлвм б®§¤ ®ўл© ᥣ¬Ґв. ќв® а §аҐи Ґв б®§¤ ў вм ®ўл© ᥣ¬Ґв, ®ЇаҐ¤Ґ«пп Є«оз.
- IPC_EXCL — нв®в д« ¦®Є, Є®в®ал© ўбҐЈ¤ ЁбЇ®«м§гҐвбп б IPC_CREAT ,§ бв ў«пҐв shmget ў®§ўа й вм ®иЁЎЄг, Ґб«Ё ᥣ¬Ґвл© Є«оз ®ЇаҐ¤Ґ«Ґ, Є Є 㦥 бгйҐбвўгойЁ©. ќв® ЁбЇ®«м§гҐвбп ¤«п ўл¤Ґ«ҐЁп «нЄбЄ«о§Ёў®Ј®» ᥣ¬Ґв . …б«Ё нв®в д« ¦®Є Ґ ¤ Ґвбп, Ё Є«оз бгйҐбвўго饣® ᥣ¬Ґв ЁбЇ®«м§гҐвбп, shmget ў®§ўа й Ґв бгйҐбвўгойЁ© ᥣ¬Ґв ў¬Ґбв® в®Ј®, зв®Ўл б®§¤ вм ®ўл©.
- Mode flags — нв® § 票Ґ Ё§ 9 ЎЁв®ў, гЄ §лў ойЁе Їа ў , ЇаҐ¤®бв ў«ҐлҐ ў« ¤Ґ«мжг, ЈагЇЇҐ, Ё ¬Ёаг(®бв «мл¬), гЇа ў«ҐЁҐ ¤®бвгЇ®¬ Є ᥣ¬Ґвг. ЃЁвл ўлЇ®«ҐЁп ЁЈ®аЁаговбп. Џа®бв®© бЇ®б®Ў ®ЇаҐ¤Ґ«Ёвм Їа ў б®бв®Ёв ў ⮬, зв®Ўл ЁбЇ®«м§®ў вм Є®бв вл, ®ЇаҐ¤Ґ«ҐлҐ ў Ё ®ЇЁб лҐ ў а §¤Ґ«Ґ 2 stat man-бва Ёж . Ќ ЇаЁ¬Ґа, S_IRUSR Ё S_IWUSR ®ЇаҐ¤Ґ«пов Їа ў з⥨Ґ Ё § ЇЁбм ¤«п ў« ¤Ґ«мж ᥣ¬Ґв ®ЎйҐ© Ї ¬пвЁ, S_IROTH Ё S_IWOTH ®ЇаҐ¤Ґ«пов Їа ў з⥨Ґ Ё § ЇЁбм ¤«п ¤агЈЁе.
Ќ ЇаЁ¬Ґа, нв®в ўл§®ў shmget б®§¤ Ґв ®ўл© ᥣ¬Ґв ®ЎйҐ© Ї ¬пвЁ (Ё«Ё ®Ўа й Ґвбп Є бгйҐбвўго饬г, Ґб«Ё shm_key 㦥 ЁбЇ®«м§гҐвбп), б Їа ў ¬Ё зЁвҐЁҐ Ё § ЇЁбм ў« ¤Ґ«м楬, ® Ґ ¤агЈЁ¬Ё Ї®«м§®ў ⥫ﬨ.
…б«Ё ўл§®ў гбЇҐиҐ, shmget ў®§ўа й Ґв Ё¤ҐвЁдЁЄ в®а ᥣ¬Ґв . …б«Ё ᥣ¬Ґв ®ЎйҐ© Ї ¬п⨠㦥 бгйҐбвўгҐв, в® Їа ў ¤®бвгЇ Їа®ўҐаҐл, Ё Їа®ўҐаЄ Ј а вЁагҐв, з⮠ᥣ¬Ґв Ґ ®в¬ҐзҐ ¤«п г¤ «ҐЁп.
Џ®¤Є«о票Ґ Ё ®вЄ«о票Ґ
—в®Ўл ᤥ« вм ᥣ¬Ґв ®ЎйҐ© Ї ¬пвЁ ¤®бвгЇл¬, Їа®жҐбб ¤®«¦Ґ ЁбЇ®«м§®ў вм shmat , » SHared Memory ATtach » ЏҐаҐ¤ ©вҐ Ґ¬г Ё¤ҐвЁдЁЄ в®а ᥣ¬Ґв ®ЎйҐ© Ї ¬пвЁ SHMID , ў®§ўа йҐл© shmget . ‚в®а®© Ї а ¬Ґва — гЄ § ⥫м, Є®в®ал© ®ЇаҐ¤Ґ«пҐв, Ј¤Ґ ў ¤аҐб®¬ Їа®бва б⢥ ў 襣® Їа®жҐбб ўл е®вЁвҐ ®в®Ўа §Ёвм ®Ўйго Ї ¬пвм; Ґб«Ё ўл ЇҐаҐ¤ ¤ЁвҐ NULL , в® Linux ўлЎҐаҐв «оЎ®© ¤®бвгЇл© ¤аҐб. ’аҐвЁ© Ї а ¬Ґва — д« ¦®Є, Є®в®ал© ¬®¦Ґв ўЄ«озЁвм б«Ґ¤гойЁҐ Ї а ¬Ґвал:
- SHM_RND гЄ §лў Ґв, зв® ¤аҐб, ®ЇаҐ¤Ґ«Ґл© ¤«п ўв®а®Ј® Ї а ¬Ґва , ¤®«¦Ґ Ўлвм ®ЄагЈ«Ґ § ¤ Є ¬®¦ЁвҐ«о а §¬Ґа бва Ёжл. …б«Ё ‚л Ґ ®ЇаҐ¤Ґ«пҐвҐ нв®в д« ¦®Є, ‚л ¤®«¦л ўла®ўпвм Ја Ёжг бва Ёжл ўв®а®© Ї а ¬Ґва ЇҐаҐ¤ ў Ґ¬л© shmat б ¬®бв®п⥫м®.
- SHM_RDONLY гЄ §лў Ґв, з⮠ᥣ¬Ґв Ўг¤Ґв ¤®бвгЇҐ в®«мЄ® ¤«п з⥨п.
- ЃЁвл Їа ў ¤®бв Ї в ЄЁҐ ¦Ґ Є Є Ё ¤«п д ©«®ў.
…б«Ё ўл§®ў гбЇҐиҐ, ® ўҐаҐв ¤аҐб Ї®¤Є«о祮Ј® ®ЎйҐЈ® ᥣ¬Ґв . Џ®в®¬ЄЁ, б®§¤ лҐ ўл§®ў ¬Ё fork , б«Ґ¤гов Ї®¤Є«озҐлҐ ®ЎйЁҐ ᥣ¬Ґвл; ®Ё ¬®Јгв ®вЄ«озЁвм ᥣ¬Ґвл ®ЎйҐ© Ї ¬пвЁ, Ґб«Ё § е®впв.
Љ®Ј¤ ўл § Є®зЁ«Ё а Ў®вг б ᥣ¬Ґв®¬ ®ЎйҐ© Ї ¬пвЁ, ᥣ¬Ґв ¤®«¦Ґ Ўлвм ®вЄ«озҐ, ЁбЇ®«м§гп shmdt (» SHared Memory DeTach «). ЏҐаҐ¤ ©вҐ Ґ¬г ¤аҐб, ў®§ўа йҐл© shmat . …б«Ё ᥣ¬Ґв Ўл« ®бў®Ў®¦¤Ґ, Ё Ў®«миҐ Ґ ®бв «®бм Їа®жҐбб®ў, ЁбЇ®«м§гойЁе ҐЈ®, ® Ўг¤Ґв г¤ «Ґ. ‚л§®ўл exit Ё exec ўв®¬ вЁзҐбЄЁ ®вЄ«оз ов ᥣ¬Ґвл.
“Їа ў«ҐЁҐ Ё ®бў®Ў®¦¤ҐЁҐ ®ЎйҐ© Ї ¬пвЁ
Shmctl (» SHared Memory ConTrol «) ўл§®ў ў®§ўа й Ґв Ёд®а¬ жЁо ®Ў ᥣ¬ҐвҐ ®ЎйҐ© Ї ¬пвЁ Ё ¬®¦Ґв Ё§¬ҐЁвм ҐЈ®.ЏҐаўл© Ї а ¬Ґва — Ё¤ҐвЁдЁЄ в®а ᥣ¬Ґв ®ЎйҐ© Ї ¬пвЁ.
—в®Ўл Ї®«гзЁвм Ёд®а¬ жЁо ® ᥣ¬ҐвҐ ®ЎйҐ© Ї ¬пвЁ, ЇҐаҐ¤ ©вҐ IPC_STAT Є Є ўв®а®© Ї а ¬Ґва Ё гЄ § ⥫м struct shmid_ds .
—в®Ўл г¤ «Ёвм ᥣ¬Ґв, ЇҐаҐ¤ ©вҐ IPC_RMID Є Є ўв®а®© Ї а ¬Ґва, Ё ЇҐаҐ¤ ©вҐ NULL Є Є ваҐвЁ© Ї а ¬Ґва. ‘ҐЈ¬Ґв г¤ «Ґ, Є®Ј¤ Ї®б«Ґ¤Ё© Їа®жҐбб, Є®в®ал© Ї®¤Є«озЁ« ҐЈ®, ®вЄ«озЁв ҐЈ®.
Љ ¦¤л© ᥣ¬Ґв ®ЎйҐ© Ї ¬пвЁ ¤®«¦Ґ Ўлвм пў® ®бў®Ў®¦¤Ґ, ЁбЇ®«м§гп shmctl , Є®Ј¤ ‚л § Є®зЁ«Ё а Ў®вг б Ё¬, зв®Ўл Ё§ЎҐ¦ вм аг襨Ґ бЁб⥬®Ј® ЇаҐ¤Ґ« а §¬Ґа Є®«ЁзҐб⢠ᥣ¬Ґв®ў ®ЎйҐ© Ї ¬пвЁ. ‚л§®ўл exit Ё exec ®вЄ«оз в ᥣ¬Ґвл Ї ¬пвЁ, ® Ґ ®бў®Ў®¦¤пв Ёе.
‘¬®ваЁ shmctl man-бва Ёжг ¤«п ®ЇЁб Ёп ¤агЈЁе ®ЇҐа жЁ©, Є®в®алҐ ¬®¦® ўлЇ®«пвм б ᥣ¬Ґв ¬Ё ®ЎйҐ© Ї ¬пвЁ.
ЏаЁ¬Ґа Їа®Ја ¬¬л
Џа®Ја ¬¬ «ЁбвЁЈ 5.1 Ё««обваЁагҐв ЁбЇ®«м§®ў ЁҐ ®ЎйҐ© Ї ¬пвЁ.
Љ®¬ ¤ ipcs ЇаҐ¤®бв ў«пҐв Ёд®а¬ жЁо ®в®бЁвҐ«м® б।бвў ў§ Ё¬®¤Ґ©бвўЁп Їа®жҐбб®ў, ўЄ«оз п ®ЎйЁҐ ᥣ¬Ґвл Ї ¬пвЁ. €бЇ®«м§г©вҐ д« Ј -m , зв®Ўл Ї®«гзЁвм Ёд®а¬ жЁо ®Ў ®ЎйҐ© Ї ¬пвЁ. Ќ ЇаЁ¬Ґа, нв®в Є®¤ Ё««обваЁагҐв з⮠ᥣ¬Ґв ®ЎйҐ© Ї ¬пвЁ, Їа®г¬Ґа®ў л© 1627649, 室Ёвбп ў ЁбЇ®«м§®ў ЁЁ:
…б«Ё нв®в ᥣ¬Ґв Ї ¬пвЁ Ўл« ®иЁЎ®з® ®бв ў«Ґ Їа®Ја ¬¬®©, ўл ¬®¦ҐвҐ ЁбЇ®«м§®ў вм Є®¬ ¤г ipcrm , зв®Ўл г¤ «Ёвм ҐЈ®.
‡ Ё Їа®вЁў
CҐЈ¬Ґвл ®ЎйҐ© Ї ¬пвЁ Ї®§ў®«пов ®бгйҐбвў«пвм Ўлбваго ¤ўг Їа ў«Ґго бўп§м б।Ё «оЎ®Ј® зЁб« Їа®жҐбб®ў. Љ ¦¤л© Ї®«м§®ў вҐ«м ¬®¦Ґв Ё зЁв вм Ё ЇЁб вм, ® Їа®Ја ¬¬ ¤®«¦ гбв ®ўЁвм Ё б«Ґ¤®ў вм ҐЄ®в®а®¬г Їа®в®Є®«г ¤«п в®Ј®, зв®Ўл ЇаҐ¤®вўа вЁвм гб«®ўЁп Ј®ЄЁ вЁЇ ЇҐаҐ§ ЇЁбЁ Ёд®а¬ жЁЁ ЇаҐ¦¤Ґ, 祬 ® Їа®зЁв Ґвбп. Љ ᮦ «ҐЁо, Linux бва®Ј® Ґ Ј а вЁагҐв нЄбЄ«о§Ёўл© ¤®бвгЇ ¤ ¦Ґ Ґб«Ё ўл б®§¤ ¤ЁвҐ ®ўл© ®ЎйЁ© ᥣ¬Ґв б IPC_PRIVATE .
Ља®¬Ґ в®Ј®, ¤«п в®Ј® зв®Ў ҐбЄ®«мЄ® Їа®жҐбб®ў ¬®Ј«Ё ЁбЇ®«м§®ў вм ®Ўйго Ї ¬пвм, ®Ё ¤®«¦л ЇаЁпвм ¬Ґал, зв®Ўл Ґ ЁбЇ®«м§®ў вм ®¤Ё Ё в®в ¦Ґ Є«оз.
Источник
Знакомство с межпроцессным взаимодействием на Linux
Межпроцессное взаимодействие (Inter-process communication (IPC)) — это набор методов для обмена данными между потоками процессов. Процессы могут быть запущены как на одном и том же компьютере, так и на разных, соединенных сетью. IPC бывают нескольких типов: «сигнал», «сокет», «семафор», «файл», «сообщение»…
Отступление: данная статья является учебной и расчитана на людей, только еще вступающих на путь системного программирования. Ее главный замысел — познакомиться с различными способами взаимодействия между процессами на POSIX-совместимой ОС.
Именованный канал
Для передачи сообщений можно использовать механизмы сокетов, каналов, D-bus и другие технологии. Про сокеты на каждом углу можно почитать, а про D-bus отдельную статью написать. Поэтому я решил остановиться на малоозвученных технологиях отвечающих стандартам POSIX и привести рабочие примеры.
Рассмотрим передачу сообщений по именованным каналам. Схематично передача выглядит так:
Для создания именованных каналов будем использовать функцию, mkfifo():
Примечание: mode используется в сочетании с текущим значением umask следующим образом: (mode &
umask). Результатом этой операции и будет новое значение umask для создаваемого нами файла. По этой причине мы используем 0777 (S_IRWXO | S_IRWXG | S_IRWXU), чтобы не затирать ни один бит текущей маски.
Как только файл создан, любой процесс может открыть этот файл для чтения или записи также, как открывает обычный файл. Однако, для корректного использования файла, необходимо открыть его одновременно двумя процессами/потоками, одним для получение данных (чтение файла), другим на передачу (запись в файл).
В случае успешного создания FIFO файла, mkfifo() возвращает 0 (нуль). В случае каких либо ошибок, функция возвращает -1 и выставляет код ошибки в переменную errno.
Типичные ошибки, которые могут возникнуть во время создания канала:
- EACCES — нет прав на запуск (execute) в одной из директорий в пути pathname
- EEXIST — файл pathname уже существует, даже если файл — символическая ссылка
- ENOENT — не существует какой-либо директории, упомянутой в pathname, либо является битой ссылкой
- ENOSPC — нет места для создания нового файла
- ENOTDIR — одна из директорий, упомянутых в pathname, на самом деле не является таковой
- EROFS — попытка создать FIFO файл на файловой системе «только-на-чтение»
Чтение и запись в созданный файл производится с помощью функций read() и write().
Пример
mkfifo.c
Мы открываем файл только для чтения (O_RDONLY). И могли бы использовать O_NONBLOCK модификатор, предназначенный специально для FIFO файлов, чтобы не ждать когда с другой стороны файл откроют для записи. Но в приведенном коде такой способ неудобен.
Компилируем программу, затем запускаем ее:
В соседнем терминальном окне выполняем:
В результате мы увидим следующий вывод от программы:
Разделяемая память
Следующий тип межпроцессного взаимодействия — разделяемая память (shared memory). Схематично изобразим ее как некую именованную область в памяти, к которой обращаются одновременно два процесса:
Для выделения разделяемой памяти будем использовать POSIX функцию shm_open():
Функция возвращает файловый дескриптор, который связан с объектом памяти. Этот дескриптор в дальнейшем можно использовать другими функциями (к примеру, mmap() или mprotect()).
Целостность объекта памяти сохраняется, включая все данные связанные с ним, до тех пор пока объект не отсоединен/удален (shm_unlink()). Это означает, что любой процесс может получить доступ к нашему объекту памяти (если он знает его имя) до тех пор, пока явно в одном из процессов мы не вызовем shm_unlink().
Переменная oflag является побитовым «ИЛИ» следующих флагов:
- O_RDONLY — открыть только с правами на чтение
- O_RDWR — открыть с правами на чтение и запись
- O_CREAT — если объект уже существует, то от флага никакого эффекта. Иначе, объект создается и для него выставляются права доступа в соответствии с mode.
- O_EXCL — установка этого флага в сочетании с O_CREATE приведет к возврату функцией shm_open ошибки, если сегмент общей памяти уже существует.
Как задается значение параметра mode подробно описано в предыдущем параграфе «передача сообщений».
После создания общего объекта памяти, мы задаем размер разделяемой памяти вызовом ftruncate(). На входе у функции файловый дескриптор нашего объекта и необходимый нам размер.
Пример
Следующий код демонстрирует создание, изменение и удаление разделяемой памяти. Так же показывается как после создания разделяемой памяти, программа выходит, но при следующем же запуске мы можем получить к ней доступ, пока не выполнен shm_unlink().
shm_open.c
После создания объекта памяти мы установили нужный нам размер shared memory вызовом ftruncate(). Затем мы получили доступ к разделяемой памяти при помощи mmap(). (Вообще говоря, даже с помощью самого вызова mmap() можно создать разделяемую память. Но отличие вызова shm_open() в том, что память будет оставаться выделенной до момента удаления или перезагрузки компьютера.)
Компилировать код на этот раз нужно с опцией -lrt:
Смотрим что получилось:
Аргумент «create» в нашей программе мы используем как для создания разделенной памяти, так и для изменения ее содержимого.
Зная имя объекта памяти, мы можем менять содержимое разделяемой памяти. Но стоит нам вызвать shm_unlink(), как память перестает быть нам доступна и shm_open() без параметра O_CREATE возвращает ошибку «No such file or directory».
Семафор
Семафор — самый часто употребляемый метод для синхронизации потоков и для контролирования одновременного доступа множеством потоков/процессов к общей памяти (к примеру, глобальной переменной). Взаимодействие между процессами в случае с семафорами заключается в том, что процессы работают с одним и тем же набором данных и корректируют свое поведение в зависимости от этих данных.
Есть два типа семафоров:
- семафор со счетчиком (counting semaphore), определяющий лимит ресурсов для процессов, получающих доступ к ним
- бинарный семафор (binary semaphore), имеющий два состояния «0» или «1» (чаще: «занят» или «не занят»)
Рассмотрим оба типа семафоров.
Семафор со счетчиком
Смысл семафора со счетчиком в том, чтобы дать доступ к какому-то ресурсу только определенному количеству процессов. Остальные будут ждать в очереди, когда ресурс освободится.
Итак, для реализации семафоров будем использовать POSIX функцию sem_open():
В функцию для создания семафора мы передаем имя семафора, построенное по определенным правилам и управляющие флаги. Таким образом у нас получится именованный семафор.
Имя семафора строится следующим образом: в начале идет символ «/» (косая черта), а следом латинские символы. Символ «косая черта» при этом больше не должен применяться. Длина имени семафора может быть вплоть до 251 знака.
Если нам необходимо создать семафор, то передается управляющий флаг O_CREATE. Чтобы начать использовать уже существующий семафор, то oflag равняется нулю. Если вместе с флагом O_CREATE передать флаг O_EXCL, то функция sem_open() вернет ошибку, в случае если семафор с указанным именем уже существует.
Параметр mode задает права доступа таким же образом, как это объяснено в предыдущих главах. А переменной value инициализируется начальное значение семафора. Оба параметра mode и value игнорируются в случае, когда семафор с указанным именем уже существует, а sem_open() вызван вместе с флагом O_CREATE.
Для быстрого открытия существующего семафора используем конструкцию:
, где указываются только имя семафора и управляющий флаг.
Пример семафора со счетчиком
Рассмотрим пример использования семафора для синхронизации процессов. В нашем примере один процесс увеличивает значение семафора и ждет, когда второй сбросит его, чтобы продолжить дальнейшее выполнение.
sem_open.c
В одной консоли запускаем:
В соседней консоли запускаем:
Бинарный семафор
Вместо бинарного семафора, для которого так же используется функция sem_open, я рассмотрю гораздо чаще употребляемый семафор, называемый «мьютекс» (mutex).
Мьютекс по существу является тем же самым, чем является бинарный семафор (т.е. семафор с двумя состояниями: «занят» и «не занят»). Но термин «mutex» чаще используется чтобы описать схему, которая предохраняет два процесса от одновременного использования общих данных/переменных. В то время как термин «бинарный семафор» чаще употребляется для описания конструкции, которая ограничивает доступ к одному ресурсу. То есть бинарный семафор используют там, где один процесс «занимает» семафор, а другой его «освобождает». В то время как мьютекс освобождается тем же процессом/потоком, который занял его.
Без мьютекса не обойтись в написании, к примеру базы данных, к которой доступ могут иметь множество клиентов.
Для использования мьютекса необходимо вызвать функцию pthread_mutex_init():
Функция инициализирует мьютекс (перемнную mutex) аттрибутом mutexattr. Если mutexattr равен NULL, то мьютекс инициализируется значением по умолчанию. В случае успешного выполнения функции (код возрата 0), мьютекс считается инициализированным и «свободным».
Типичные ошибки, которые могут возникнуть:
- EAGAIN — недостаточно необходимых ресурсов (кроме памяти) для инициализации мьютекса
- ENOMEM — недостаточно памяти
- EPERM — нет прав для выполнения операции
- EBUSY — попытка инициализировать мьютекс, который уже был инициализирован, но не унечтожен
- EINVAL — значение mutexattr не валидно
Чтобы занять или освободить мьютекс, используем функции:
Функция pthread_mutex_lock(), если mutex еще не занят, то занимает его, становится его обладателем и сразу же выходит. Если мьютекс занят, то блокирует дальнейшее выполнение процесса и ждет освобождения мьютекса.
Функция pthread_mutex_trylock() идентична по поведению функции pthread_mutex_lock(), с одним исключением — она не блокирует процесс, если mutex занят, а возвращает EBUSY код.
Фунция pthread_mutex_unlock() освобождает занятый мьютекс.
Коды возврата для pthread_mutex_lock():
- EINVAL — mutex неправильно инициализирован
- EDEADLK — мьютекс уже занят текущим процессом
Коды возврата для pthread_mutex_trylock():
- EBUSY — мьютекс уже занят
- EINVAL — мьютекс неправильно инициализирован
Коды возврата для pthread_mutex_unlock():
- EINVAL — мьютекс неправильно инициализирован
- EPERM — вызывающий процесс не является обладателем мьютекса
Пример mutex
mutex.c
Данный пример демонстрирует совместный доступ двух потоков к общей переменной. Один поток (первый поток) в автоматическом режиме постоянно увеличивает переменную counter на единицу, при этом занимая эту переменную на целую секунду. Этот первый поток дает второму доступ к переменной count только на 10 миллисекунд, затем снова занимает ее на секунду. Во втором потоке предлагается ввести новое значение для переменной с терминала.
Если бы мы не использовали технологию «мьютекс», то какое значение было бы в глобальной переменной, при одновременном доступе двух потоков, нам не известно. Так же во время запуска становится очевидна разница между pthread_mutex_lock() и pthread_mutex_trylock().
Компилировать код нужно с дополнительным параметром -lpthread:
Запускаем и меняем значение переменной просто вводя новое значение в терминальном окне:
Вместо заключения
В следующих статьях я хочу рассмотреть технологии d-bus и RPC. Если есть интерес, дайте знать.
Спасибо.
UPD: Обновил 3-ю главу про семафоры. Добавил подглаву про мьютекс.
Источник