Օպերացիոն համակարգեր. երեք հեշտ կտոր: Մաս 3. Գործընթացի API (թարգմանություն)

Օպերացիոն համակարգերի ներածություն

Հե՜յ Հաբր։ Ձեր ուշադրությանն եմ ներկայացնում իմ կարծիքով մեկ հետաքրքիր գրականության՝ OSTEP-ի հոդված-թարգմանությունների շարքը։ Այս նյութը բավականին խորը քննարկում է unix-ի նման օպերացիոն համակարգերի աշխատանքը, այն է՝ պրոցեսների, տարբեր ժամանակացույցերի, հիշողության և այլ նմանատիպ բաղադրիչների հետ աշխատանքը, որոնք կազմում են ժամանակակից ՕՀ: Բոլոր նյութերի բնօրինակը կարող եք տեսնել այստեղ այստեղ. Խնդրում եմ նկատի ունենալ, որ թարգմանությունը կատարվել է ոչ պրոֆեսիոնալ (բավականին ազատ), բայց հուսով եմ պահպանել եմ ընդհանուր իմաստը։

Այս թեմայով լաբորատոր աշխատանք կարելի է գտնել այստեղ.

Այլ մասեր.

Կարող եք նաև դիտել իմ ալիքը հեռագիր =)

Ահազանգ Այս դասախոսության համար կա լաբորատորիա: Նայել github

Գործընթացի API

Դիտարկենք UNIX համակարգում գործընթաց ստեղծելու օրինակ: Դա տեղի է ունենում երկու համակարգային զանգերի միջոցով պատառաքաղ () и exec ().

Call fork ()

Օպերացիոն համակարգեր. երեք հեշտ կտոր: Մաս 3. Գործընթացի API (թարգմանություն)

Դիտարկենք մի ծրագիր, որը կատարում է fork() զանգ: Դրա կատարման արդյունքը կլինի հետևյալը.

Օպերացիոն համակարգեր. երեք հեշտ կտոր: Մաս 3. Գործընթացի API (թարգմանություն)

Առաջին հերթին մենք մուտքագրում ենք main() ֆունկցիան և տպում տողը էկրանին։ Տողը պարունակում է գործընթացի նույնացուցիչը, որը բնօրինակում կոչվում է PID կամ գործընթացի նույնացուցիչը: Այս նույնացուցիչն օգտագործվում է UNIX-ում՝ գործընթացին անդրադառնալու համար: Հաջորդ հրամանը կկանչի fork(). Այս պահին ստեղծվում է գործընթացի գրեթե ճշգրիտ պատճենը: ՕՀ-ի համար, թվում է, թե համակարգում գործում է նույն ծրագրի 2 օրինակ, որն իր հերթին դուրս կգա fork() ֆունկցիայից: Նորաստեղծ երեխա պրոցեսը (կապված այն ստեղծած ծնող գործընթացի հետ) այլևս չի կատարվի՝ սկսած main() ֆունկցիայից։ Պետք է հիշել, որ երեխայի պրոցեսը ծնող գործընթացի ճշգրիտ պատճենը չէ, մասնավորապես, այն ունի իր հասցեների տարածքը, սեփական ռեգիստրները, գործարկվող հրահանգների իր ցուցիչը և այլն: Այսպիսով, fork() ֆունկցիայի կանչողին վերադարձված արժեքը տարբեր կլինի։ Մասնավորապես, մայր պրոցեսը որպես վերադարձ կստանա երեխայի պրոցեսի PID արժեքը, իսկ երեխան կստանա 0-ի արժեք: Օգտագործելով այս վերադարձի կոդերը, դուք կարող եք այնուհետև առանձնացնել գործընթացները և ստիպել նրանցից յուրաքանչյուրին կատարել իր աշխատանքը: . Այնուամենայնիվ, այս ծրագրի կատարումը խստորեն սահմանված չէ: 2 պրոցեսների բաժանվելուց հետո ՕՀ-ն սկսում է վերահսկել դրանք, ինչպես նաև պլանավորել նրանց աշխատանքը։ Եթե ​​գործարկվի մեկ միջուկային պրոցեսորի վրա, պրոցեսներից մեկը, այս դեպքում ծնողը, կշարունակի աշխատել, և այնուհետև երեխայի գործընթացը կստանա վերահսկողություն: Վերագործարկման ժամանակ իրավիճակը կարող է տարբեր լինել:

Զանգի սպասել ()

Օպերացիոն համակարգեր. երեք հեշտ կտոր: Մաս 3. Գործընթացի API (թարգմանություն)

Դիտարկենք հետևյալ ծրագիրը. Այս ծրագրում զանգի առկայության պատճառով սպասիր () Ծնողական գործընթացը միշտ կսպասի երեխայի գործընթացի ավարտին: Այս դեպքում մենք էկրանին կստանանք խիստ սահմանված տեքստային ելք

Օպերացիոն համակարգեր. երեք հեշտ կտոր: Մաս 3. Գործընթացի API (թարգմանություն)

exec() զանգ

Օպերացիոն համակարգեր. երեք հեշտ կտոր: Մաս 3. Գործընթացի API (թարգմանություն)

Հաշվի առեք մարտահրավերը exec (). Այս համակարգային զանգը օգտակար է, երբ մենք ցանկանում ենք գործարկել բոլորովին այլ ծրագիր: Այստեղ մենք կկանչենք execvp () գործարկել wc ծրագիրը, որը բառերի հաշվման ծրագիր է: Ի՞նչ է պատահում, երբ կանչվում է exec(): Այս զանգին փոխանցվում է գործարկվող ֆայլի անունը և որոշ պարամետրեր՝ որպես արգումենտ: Որից հետո այս գործարկվող ֆայլի կոդը և ստատիկ տվյալները բեռնվում են և ծածկագրով սեփական հատվածը վերագրվում է: Մնացած հիշողության տարածքները, ինչպիսիք են կույտը և կույտը, վերսկսվում են: Որից հետո ՕՀ-ն պարզապես կատարում է ծրագիրը՝ փոխանցելով նրան մի շարք փաստարկներ։ Այսպիսով, մենք նոր պրոցես չստեղծեցինք, մենք ուղղակի գործող ծրագիրը փոխակերպեցինք մեկ այլ գործող ծրագրի: Հետնորդում exec() կանչը կատարելուց հետո թվում է, թե սկզբնական ծրագիրը ընդհանրապես չի գործարկվել։

Գործարկման այս բարդությունը լիովին նորմալ է Unix shell-ի համար և թույլ է տալիս այդ կեղևը գործարկել կոդը զանգից հետո: պատառաքաղ (), բայց զանգից առաջ exec (). Նման կոդի օրինակ կարող է լինել shell միջավայրի հարմարեցումը գործարկվող ծրագրի կարիքներին՝ նախքան այն գործարկելը:

Խեցի - պարզապես օգտագործողի ծրագիր: Նա ձեզ ցույց է տալիս հրավերի գիծը և սպասում, որ դուք ինչ-որ բան գրեք դրա մեջ: Շատ դեպքերում, եթե այնտեղ գրեք ծրագրի անվանումը, ապա կեղևը կգտնի իր գտնվելու վայրը, կկանչի fork() մեթոդը և այնուհետև կկանչի exec() մի տեսակ՝ նոր գործընթաց ստեղծելու համար և սպասելու, որ այն ավարտվի՝ օգտագործելով a. սպասել() զանգ. Երբ երեխայի պրոցեսը դուրս գա, կեղևը կվերադառնա սպասման () զանգից և նորից կտպագրի հուշումը և կսպասի հաջորդ հրամանի մուտքագրմանը:

Fork() & exec() բաժանումը թույլ է տալիս shell-ին անել հետևյալ գործողությունները, օրինակ.
wc ֆայլ > new_file.

Այս օրինակում wc ծրագրի ելքը վերահղված է ֆայլ: Այն, թե ինչպես է կեղևը հասնում դրան, բավականին պարզ է՝ նախքան զանգահարելը ստեղծելով երեխայի գործընթաց exec (), կեղևը փակում է ստանդարտ ելքը և բացում ֆայլը նոր_ֆայլ, այսպիսով, ամբողջ արդյունքը հետագա գործող ծրագրից wc էկրանի փոխարեն կվերահղվի ֆայլ:

Unix խողովակ իրականացվում են նմանատիպ եղանակով, այն տարբերությամբ, որ օգտագործում են pipe() կանչ: Այս դեպքում պրոցեսի ելքային հոսքը կմիանա միջուկում գտնվող խողովակի հերթին, որին կմիանա մեկ այլ պրոցեսի մուտքային հոսքը։

Source: www.habr.com

Добавить комментарий