Mga Operating System: Tatlong Madaling Piraso. Bahagi 3: Process API (pagsasalin)

Panimula sa Mga Operating System

Hello, Habr! Nais kong ipakita sa iyong pansin ang isang serye ng mga artikulo-pagsasalin ng isang panitikan na kawili-wili sa aking opinyon - OSTEP. Malalim na sinusuri ng materyal na ito ang gawain ng mga operating system na katulad ng unix, ibig sabihin, gumagana sa mga proseso, iba't ibang mga scheduler, memorya at iba pang katulad na mga bahagi na bumubuo sa isang modernong OS. Maaari mong makita ang orihinal ng lahat ng mga materyales dito dito. Pakitandaan na ang pagsasalin ay ginawa nang hindi propesyonal (medyo malaya), ngunit sana ay pinanatili ko ang pangkalahatang kahulugan.

Ang gawain sa laboratoryo sa paksang ito ay matatagpuan dito:

Iba pang parte:

Maaari mo ring tingnan ang aking channel sa telegram =)

Alarm! May lab para sa lecture na ito! Tingnan mo github

Process API

Tingnan natin ang isang halimbawa ng paglikha ng isang proseso sa isang UNIX system. Nangyayari ito sa pamamagitan ng dalawang tawag sa system tinidor () ΠΈ exec().

Tawagan ang tinidor ()

Mga Operating System: Tatlong Madaling Piraso. Bahagi 3: Process API (pagsasalin)

Isaalang-alang ang isang programa na gumagawa ng fork() na tawag. Ang resulta ng pagpapatupad nito ay ang mga sumusunod.

Mga Operating System: Tatlong Madaling Piraso. Bahagi 3: Process API (pagsasalin)

Una sa lahat, ipinasok namin ang main() function at i-print ang string sa screen. Ang linya ay naglalaman ng identifier ng proseso na sa orihinal ay tinatawag PID o identifier ng proseso. Ang identifier na ito ay ginagamit sa UNIX upang sumangguni sa isang proseso. Ang susunod na command ay tatawag ng fork(). Sa puntong ito, isang halos eksaktong kopya ng proseso ay nilikha. Para sa OS, mukhang mayroong 2 kopya ng parehong program na tumatakbo sa system, na lalabas naman sa fork() function. Ang bagong likhang proseso ng bata (kaugnay ng proseso ng magulang na lumikha nito) ay hindi na isasagawa, simula sa main() function. Dapat tandaan na ang proseso ng bata ay hindi isang eksaktong kopya ng proseso ng magulang; lalo na, mayroon itong sariling puwang ng address, sarili nitong mga rehistro, sariling pointer sa mga maipapatupad na tagubilin, at iba pa. Kaya, ang halaga na ibinalik sa tumatawag ng fork() function ay magkakaiba. Sa partikular, ang proseso ng magulang ay makakatanggap ng halaga ng PID ng proseso ng bata bilang isang pagbabalik, at ang bata ay makakatanggap ng isang halaga na katumbas ng 0. Gamit ang mga return code na ito, maaari mong paghiwalayin ang mga proseso at pilitin ang bawat isa sa kanila na gawin ang sarili nitong gawain . Gayunpaman, ang pagpapatupad ng programang ito ay hindi mahigpit na tinukoy. Matapos hatiin sa 2 proseso, ang OS ay nagsisimulang subaybayan ang mga ito, pati na rin ang pagpaplano ng kanilang trabaho. Kung naisakatuparan sa isang single-core na processor, ang isa sa mga proseso, sa kasong ito, ang magulang, ay magpapatuloy sa pagtatrabaho, at pagkatapos ay ang proseso ng bata ay makakatanggap ng kontrol. Kapag nag-restart, maaaring iba ang sitwasyon.

Tawagan wait()

Mga Operating System: Tatlong Madaling Piraso. Bahagi 3: Process API (pagsasalin)

Isaalang-alang ang sumusunod na programa. Sa programang ito, dahil sa pagkakaroon ng isang tawag maghintay () Ang proseso ng magulang ay palaging maghihintay para makumpleto ang proseso ng bata. Sa kasong ito, makakakuha tayo ng isang mahigpit na tinukoy na output ng teksto sa screen

Mga Operating System: Tatlong Madaling Piraso. Bahagi 3: Process API (pagsasalin)

exec() na tawag

Mga Operating System: Tatlong Madaling Piraso. Bahagi 3: Process API (pagsasalin)

Isaalang-alang ang hamon exec(). Ang system call na ito ay kapaki-pakinabang kapag gusto naming magpatakbo ng isang ganap na naiibang programa. Dito tayo tatawag execvp() upang patakbuhin ang wc program na isang word counting program. Ano ang mangyayari kapag tinawag ang exec()? Ang tawag na ito ay ipinasa ang pangalan ng executable file at ilang mga parameter bilang mga argumento. Pagkatapos kung saan ang code at static na data mula sa executable file na ito ay na-load at ang sarili nitong segment na may code ay na-overwrite. Ang natitirang mga lugar ng memorya, tulad ng stack at heap, ay muling sinisimulan. Pagkatapos kung saan ang OS ay nagpapatupad lamang ng programa, ipinapasa ito ng isang hanay ng mga argumento. Kaya hindi kami gumawa ng bagong proseso, binago lang namin ang kasalukuyang tumatakbong programa sa isa pang tumatakbong programa. Pagkatapos isagawa ang exec() na tawag sa descendant, lumilitaw na parang hindi tumakbo ang orihinal na programa.

Ang komplikasyon sa startup na ito ay ganap na normal para sa isang Unix shell, at pinapayagan ang shell na iyon na magsagawa ng code pagkatapos tumawag tinidor (), ngunit bago ang tawag exec(). Ang isang halimbawa ng naturang code ay ang pagsasaayos ng shell environment sa mga pangangailangan ng program na inilulunsad, bago ito ilunsad.

Talukap ng alimango - isang user program lang. Ipinakita niya sa iyo ang linya ng imbitasyon at naghihintay na magsulat ka rito. Sa karamihan ng mga kaso, kung isusulat mo ang pangalan ng isang programa doon, makikita ng shell ang lokasyon nito, tatawagan ang fork() na paraan, at pagkatapos ay tumawag ng ilang uri ng exec() upang lumikha ng bagong proseso at hintayin itong makumpleto gamit ang isang wait() tawag. Kapag lumabas ang proseso ng bata, babalik ang shell mula sa wait() na tawag at i-print muli ang prompt at hintayin ang susunod na command na maipasok.

Ang fork() & exec() split ay nagpapahintulot sa shell na gawin ang mga sumusunod na bagay, halimbawa:
wc file > new_file.

Sa halimbawang ito, ang output ng wc program ay na-redirect sa isang file. Ang paraan ng pagkamit ng shell ay medyo simple - sa pamamagitan ng paglikha ng isang proseso ng bata bago tumawag exec(), isinasara ng shell ang karaniwang output at binubuksan ang file bagong file, kaya, lahat ng output mula sa karagdagang tumatakbong programa wc ay ire-redirect sa isang file sa halip na isang screen.

Unix pipe ay ipinatupad sa katulad na paraan, na may pagkakaiba na gumagamit sila ng pipe() na tawag. Sa kasong ito, ang output stream ng proseso ay ikokonekta sa isang pipe queue na matatagpuan sa kernel, kung saan ang input stream ng isa pang proseso ay ikokonekta.

Pinagmulan: www.habr.com

Magdagdag ng komento