Операциялық жүйелер: үш оңай бөлік. 3-бөлім: Process API (аударма)

Операциялық жүйелермен таныстыру

Эй Хабр! Мен сіздердің назарларыңызға менің ойымша, бір қызықты әдебиеттің аудармалары – OSTEP мақалалар топтамасын ұсынғым келеді. Бұл материалда UNIX тәрізді операциялық жүйелердің жұмысы, атап айтқанда, қазіргі ОЖ құрайтын процестермен, әртүрлі жоспарлаушылармен, жадпен және басқа ұқсас компоненттермен жұмыс өте терең қарастырылады. Мұнда сіз барлық материалдардың түпнұсқасын көре аласыз осында. Аударма кәсіби емес (өте еркін) жасалғанын ескеріңіз, бірақ мен жалпы мағынаны сақтап қалдым деп үміттенемін.

Осы тақырып бойынша зертханалық жұмысты мына жерден табуға болады:

Басқа бөліктер:

Сондай-ақ менің арнамды мына жерден көре аласыз жеделхаттар =)

Дабыл! Бұл дәріс үшін зертхана бар! Қараңыз github

Процесс API

UNIX жүйесінде процесті құру мысалын қарастырайық. Бұл екі жүйелік шақыру арқылы болады шанышқы () и exec().

Call fork()

Операциялық жүйелер: үш оңай бөлік. 3-бөлім: Process API (аударма)

fork() шақыруын жасайтын бағдарламаны қарастырайық. Оның орындалуының нәтижесі келесідей болады.

Операциялық жүйелер: үш оңай бөлік. 3-бөлім: Process API (аударма)

Ең алдымен, біз main() функциясын енгіземіз және жолды экранға басып шығарамыз. Жолда түпнұсқада аталған процесс идентификаторы бар PID немесе процесс идентификаторы. Бұл идентификатор UNIX жүйесінде процеске сілтеме жасау үшін пайдаланылады. Келесі пәрмен fork() деп аталады. Осы кезде процестің дәл дерлік көшірмесі жасалады. ОЖ үшін жүйеде жұмыс істейтін бірдей бағдарламаның 2 көшірмесі бар сияқты, ол өз кезегінде fork() функциясынан шығады. Жаңадан жасалған еншілес процесс (оны жасаған негізгі процеске қатысты) main() функциясынан бастап енді орындалмайды. Еншілес процесс ата-аналық процестің дәл көшірмесі емес екенін есте ұстаған жөн, атап айтқанда, оның өз адрестік кеңістігі, өзінің регистрлері, орындалатын нұсқауларға арналған жеке көрсеткіші және т.б. Осылайша, fork() функциясының шақырушысына қайтарылған мән басқаша болады. Атап айтқанда, ата-аналық процесс қайтару ретінде еншілес процестің PID мәнін алады, ал бала 0-ге тең мәнді алады. Осы қайтару кодтарын пайдалана отырып, процестерді бөліп, олардың әрқайсысын өз жұмысын орындауға мәжбүрлей аласыз. . Дегенмен, бұл бағдарламаның орындалуы қатаң анықталмаған. 2 процесске бөлінгеннен кейін ОЖ оларды бақылауға, сондай-ақ олардың жұмысын жоспарлауға кіріседі. Егер бір ядролы процессорда орындалса, процестердің бірі, бұл жағдайда ата-ана, жұмысын жалғастырады, содан кейін еншілес процесс басқаруды алады. Қайта іске қосу кезінде жағдай басқаша болуы мүмкін.

Қоңырау күту()

Операциялық жүйелер: үш оңай бөлік. 3-бөлім: Process API (аударма)

Келесі бағдарламаны қарастырыңыз. Бұл бағдарламада қоңыраудың болуына байланысты күтіңіз() Ата-аналық процесс әрқашан еншілес процестің аяқталуын күтеді. Бұл жағдайда біз экранда қатаң анықталған мәтіндік шығысты аламыз

Операциялық жүйелер: үш оңай бөлік. 3-бөлім: Process API (аударма)

exec() шақыру

Операциялық жүйелер: үш оңай бөлік. 3-бөлім: Process API (аударма)

Қиындықты қарастырыңыз exec(). Бұл жүйелік қоңырау біз мүлде басқа бағдарламаны іске қосқымыз келгенде пайдалы. Міне, біз қоңырау шаламыз execvp() Сөздерді санау бағдарламасы болып табылатын wc бағдарламасын іске қосу үшін. exec() шақырылғанда не болады? Бұл шақыруға орындалатын файлдың аты және кейбір параметрлер аргумент ретінде беріледі. Осыдан кейін осы орындалатын файлдағы код пен статикалық деректер жүктеледі және кодпен өз сегменті қайта жазылады. Стек және үйме сияқты қалған жад аймақтары қайта инициализацияланады. Осыдан кейін ОЖ жай ғана бағдарламаны орындайды, оған дәлелдер жиынтығын береді. Сондықтан біз жаңа процесті жасамадық, біз жай ғана ағымдағы жұмыс істеп тұрған бағдарламаны басқа іске қосылған бағдарламаға айналдырдық. Exec() шақыруын ұрпақта орындағаннан кейін бастапқы бағдарлама мүлде іске қосылмаған сияқты болады.

Бұл іске қосу қиындығы Unix қабығы үшін мүлдем қалыпты және бұл қабықшаға қоңырау шалғаннан кейін кодты орындауға мүмкіндік береді. шанышқы (), бірақ қоңырау алдында exec(). Мұндай кодтың мысалы ретінде қабық ортасын іске қосу алдында іске қосылатын бағдарламаның қажеттіліктеріне сәйкес келтіруге болады.

Shell - жай ғана пайдаланушы бағдарламасы. Ол сізге шақыру жолын көрсетіп, оған бірдеңе жазуыңызды күтеді. Көп жағдайда бағдарламаның атын сол жерге жазсаңыз, қабық оның орнын табады, fork() әдісін шақырады, содан кейін жаңа процесті жасау үшін exec() түрін шақырады және оның көмегімен оның аяқталуын күтеді. wait() қоңырауы. Еншілес процесс шыққан кезде, қабық wait() шақыруынан оралады және шақыруды қайтадан басып шығарады және келесі пәрменді енгізуді күтеді.

Fork() және exec() бөлу қабықшаға келесі әрекеттерді орындауға мүмкіндік береді, мысалы:
wc файлы > жаңа_файл.

Бұл мысалда wc бағдарламасының шығысы файлға қайта бағытталады. Қабықтың бұған жету жолы өте қарапайым - қоңырау шалу алдында еншілес процесті жасау арқылы exec(), қабық стандартты шығысты жауып, файлды ашады жаңа_файл, осылайша, әрі қарай іске қосылған бағдарламаның барлық шығысы wc экранның орнына файлға қайта бағытталады.

Unix құбыры ұқсас жолмен жүзеге асырылады, айырмашылығы олар pipe() шақыруын пайдаланады. Бұл жағдайда процестің шығыс ағыны ядрода орналасқан құбыр кезегіне қосылады, оған басқа процестің кіріс ағыны қосылады.

Ақпарат көзі: www.habr.com

пікір қалдыру