Sistemes operatius: tres peces fàcils. Part 3: API de procés (traducció)

Introducció als sistemes operatius

Hola Habr! M'agradaria cridar la vostra atenció una sèrie d'articles-traduccions d'una literatura interessant al meu entendre: OSTEP. Aquest material tracta bastant profundament el treball dels sistemes operatius semblants a Unix, és a dir, el treball amb processos, diversos programadors, memòria i altres components similars que conformen un sistema operatiu modern. Podeu veure l'original de tots els materials aquí aquí. Si us plau, tingueu en compte que la traducció es va fer de manera poc professional (molt lliure), però espero haver conservat el sentit general.

Els treballs de laboratori sobre aquest tema es poden trobar aquí:

Altres parts:

També pots consultar el meu canal a telegrama =)

Alarma! Hi ha un laboratori per a aquesta conferència! Mira github

API de procés

Vegem un exemple de creació d'un procés en un sistema UNIX. Passa a través de dues trucades al sistema forquilla () и exec().

Forquilla de trucades ()

Sistemes operatius: tres peces fàcils. Part 3: API de procés (traducció)

Penseu en un programa que fa una crida a fork(). El resultat de la seva execució serà el següent.

Sistemes operatius: tres peces fàcils. Part 3: API de procés (traducció)

Primer de tot, entrem a la funció main() i imprimim la cadena a la pantalla. La línia conté l'identificador del procés que a l'original s'anomena PID o identificador del procés. Aquest identificador s'utilitza a UNIX per referir-se a un procés. La següent comanda cridarà a fork(). En aquest punt, es crea una còpia gairebé exacta del procés. Per al sistema operatiu, sembla que hi ha 2 còpies del mateix programa en execució al sistema, que al seu torn sortirà de la funció fork(). El procés fill acabat de crear (en relació amb el procés pare que el va crear) ja no s'executarà, començant per la funció main(). Cal recordar que un procés fill no és una còpia exacta del procés pare; en particular, té el seu propi espai d'adreces, els seus propis registres, el seu propi punter a instruccions executables i similars. Així, el valor retornat a la persona que truca de la funció fork() serà diferent. En particular, el procés principal rebrà el valor PID del procés secundari com a retorn, i el fill rebrà un valor igual a 0. Amb aquests codis de retorn, podeu separar els processos i obligar a cadascun d'ells a fer el seu propi treball. . Tanmateix, l'execució d'aquest programa no està estrictament definida. Després de dividir-se en 2 processos, el sistema operatiu comença a supervisar-los, així com a planificar-ne el treball. Si s'executa en un processador d'un sol nucli, un dels processos, en aquest cas el pare, continuarà funcionant i, aleshores, el procés fill rebrà el control. En reiniciar, la situació pot ser diferent.

Truca espera ()

Sistemes operatius: tres peces fàcils. Part 3: API de procés (traducció)

Considereu el programa següent. En aquest programa, a causa de la presència d'una trucada espera () El procés principal sempre esperarà que finalitzi el procés secundari. En aquest cas, obtindrem una sortida de text estrictament definida a la pantalla

Sistemes operatius: tres peces fàcils. Part 3: API de procés (traducció)

crida a exec().

Sistemes operatius: tres peces fàcils. Part 3: API de procés (traducció)

Considereu el repte exec(). Aquesta crida al sistema és útil quan volem executar un programa completament diferent. Aquí trucarem execvp() per executar el programa wc que és un programa de recompte de paraules. Què passa quan es crida a exec()? Aquesta crida passa el nom del fitxer executable i alguns paràmetres com a arguments. Després es carreguen el codi i les dades estàtiques d'aquest fitxer executable i se sobreescriu el seu propi segment amb el codi. Les àrees de memòria restants, com ara la pila i l'emmagatzematge dinàmic, es reinicialitzen. Després d'això, el sistema operatiu simplement executa el programa, passant-li un conjunt d'arguments. Així que no hem creat un procés nou, simplement hem transformat el programa en execució en un altre programa en execució. Després d'executar la crida exec() al descendent, sembla com si el programa original no s'hagués executat en absolut.

Aquesta complicació d'inici és completament normal per a un shell Unix i permet que aquest shell executi codi després de trucar forquilla (), però abans de la trucada exec(). Un exemple d'aquest codi seria ajustar l'entorn de l'intèrpret d'ordres a les necessitats del programa que s'està llançant, abans de llançar-lo.

Concha - només un programa d'usuari. Ella us mostra la línia d'invitació i espera que hi escriviu alguna cosa. En la majoria dels casos, si escriviu el nom d'un programa allà, l'intèrpret d'ordres trobarà la seva ubicació, trucarà al mètode fork() i després trucarà a algun tipus d'exec() per crear un procés nou i esperarà que finalitzi amb un wait() trucada. Quan el procés fill surt, l'intèrpret d'ordres tornarà de la crida wait() i imprimirà de nou l'indicador i esperarà que s'introdueixi la següent ordre.

La divisió fork() & exec() permet que l'intèrpret d'ordres faci les coses següents, per exemple:
wc fitxer > nou_fitxer.

En aquest exemple, la sortida del programa wc es redirigeix ​​a un fitxer. La manera com l'intèrpret d'ordres ho aconsegueix és bastant senzill: creant un procés fill abans de trucar exec(), el shell tanca la sortida estàndard i obre el fitxer fitxer_nou, per tant, tota la sortida del programa en execució posterior wc es redirigirà a un fitxer en lloc d'una pantalla.

Pipa Unix s'implementen de manera similar, amb la diferència que utilitzen una trucada pipe(). En aquest cas, el flux de sortida del procés es connectarà a una cua de canonades situada al nucli, a la qual es connectarà el flux d'entrada d'un altre procés.

Font: www.habr.com

Afegeix comentari