Professional Documents
Culture Documents
Untitled
Untitled
Hyrje
Sistemi operativ është pjesë e rëndësishme e gati secilit sistem kompjuterik. Sistemin
kompjuterik mund ta ndajmë në katër komponente. Ato janë:
Hardveri (njësia qendrore, memoria, njësitë hyrëse-dalëse.
Sistemi operativ.
Programet aplikative (kompajlerët, programet financiare, video-lojrat, programet për
udhëheqjen e bazave të të dhënave etj.).
Shfrytëzuesit (njerëzit, makinat ose kompjuterët tjerë).
Hardveri siguron resurset themelore për përpunim të të dhënave. Aplikacionet definojnë
mënyrën se si këto resurse do të shfrytëzohen me qëllim të zhgjidhjes së problemeve të shfrytëzu
esve. Sistemin kompjuterik mund ta shfrytëzojnë më shumë shfrytëzues që tentojnë të zgjedhin
probleme të ndryshme. Rrjedhimisht mund të ketë më shumë programe aplikative. Sistemi
operativ kontrollon dhe koordinon shfrytëzimin e hardverit mes aplikacioneve të
ndryshme të shfrytëzuesve të ndryshëm.
Sistemi operativ vet për vehte nuk kryen ndonjë punë që do të mund të shfrytëzohej. Këtë
e bëjnë hardveri, programet dhe të dhënat e shfrytëzuesit. Sistemi operativ vetëm ofron mjetet për
përdorim me vend të resurseve kompjuterike. Themi se sistemi operativ siguron rrethinën në
të cilën programet tjera mund të kryejnë punë të dobishme.
Sistemi kompjuterik ka më shumë resurse që mund të jenë të kërkuara për zgjidhjen e
problemit, siç janë për shembull koha e njësisë qendrore, hapësira memorike, njësitë hyrëse-dalëse
etj. Sistemi operativ mund të trajtohet si shpërndarës i këtyre resurseve. Pasi mund të paraqiten
më shumë kërkesa për resurse të njejta, është detyrë e sistemit operativ që të zgjidhë situatat e
tilla në mënyrë të drejtë dhe efikase.
Nevoja që sistemi operativ të përqëndrohet në kontrollin e operacioneve të hyrje-daljes
dhe programeve të shfrytëzuesit ka dhënë shkas që sistemi operativ të trajtohet si program
kontrollues. Programi kontrollues kontrollon punën e programeve me qëllim të parandalimit të
gabimeve dhe shfrytëzimit jo të drejtë të kompjuterit. Qëllimi i tij primar është puna dhe kontrolli i
njësive hyrëse-dalëse.
1
Fig.1.1 Komponenetet e sistemit kompjuterik
Do të mund të themi në fund se sistemet operative ekzistojnë për arsye se ata janë mënyrë
e arsyeshme për zgjidhjen e problemit të krijimit të sistemit të shfyrëtzueshëm kompjuterik.
Qëllimi i kompjuterëve është zgjidhja e problemeve të shfrytëzuesve. Duke pasë këtë ndër mend
është realizuar hardveri i kompjuterit. Mirëpo vetë hardveri nuk është i përshtatshëm për
shfrytëzim. Kjo ka paraqitë nevojën e shkruarjes së programeve aplikative. Këto programe
aplikative kanë nevojë për kryerjen e disa operacioneve të cilat janë të njejta ose të ngjashme për
të gjitha ato, siç janë për shembull, operacionet e hyrje-daljes. Së fundi, këto dhe të gjitha
funksionet e përbashkëta të kontrollit dhe shpërndarjes së resurseve kompjuterike janë organizuar
si një tërësi programore e njohur si sistem operativ. Qëllimi i parë i sistemit operativ është që ta
bëjë kompjuterin të përshtatshëm për shfrytëzuesin.
Qëllimi i dytë i sistemit operativ është shfrytëzimi efikas i sistemit kompjuterik. Kjo
është posaçërisht e rëndësishme për sistemet e mëdha. Sistemet e tilla janë të shtrenjta dhe çdo
rritje e efikasitetit të punës së tyre do të mirëpritej.
Sistemet operative dhe arkitektura e kompjuterit kanë ndikim të madh në njëri tjetrin. Për
të mundësuar përdorimin më të lehtë të hardverit janë krijuar sistemet e para operative. Zhvillimi i
sistemeve operative ka shtruar nevojën e avancimit të zgjidhjeve hardverike me qëllim të
thjeshtësimit të dizajnimit dhe rritjes së efikasitetit të sistemeve operative. Në vazhdim do japim
2
një pasqyrë të shkurtë të zhvillimit të sistemeve operative dhe ndikimit reciprok me arkitekturën e
kompjuterëve për të cilët janë përpiluar.
3
Fig.1.2 Vendosja në memorie e monitorit rezident
4
rregullt ose jo të rregullt kontrolli mbi kompjuterin i është kthyer monitorit i cili pastaj ka startuar
ndonjë punë tjetër.
Që monitori të dijë se çfarë pune do të kryhet në kompjuter, janë paraqitë të
ashtuquajturat kartelat kontrolluese. Nëse shfrytëzuesi ka dashur ta ekzekutojë programin e
shkruar në Fortran, atëherë për të kryer këtë punë ka qenë e nevojshme të thirret kompajleri për
Fortran, asembleri (pasi kompajlerët e hershëm kanë dhënë në dalje kodin asemblerik) dhe në
fund të startohet programi. Për secilin aksion është dhënë kartela kontrolluese e veçantë, pra:
$FTN për të ekzekutuar kompjalerin për Fortran,
$ASM për të ekzekutuar asemblerin,
$RUN për të ekzekutuar programin e shfrytëzuesit.
Këto kartela i tregonin monitorit se cilat programe duhet startuar. Për të kufizuar secilën punë të
veçantë që duhej kryer nga kompjuteri u paraqitën edhe dy kartela kontrolluese:
$JOB që paraqet kartelën e parë të secilës punë dhe
$END që paraqet kartelën e fundit të secilës punë.
Për të kryer punë tjera janë shfrytëzuar kartela tjera kontrolluese. Që kartelat kontrolluese të
dallohen nga kartelat që përmbajnë të dhënat dhe instruksionet e programit në fillim të
përmbajtjes së secilës është shenuar simboli $ ose //.
Nga kjo që u tha mund të konkludojmë se monitori rezident kishte disa pjesë që kryenin
funksione të ndryshme. Këto janë interpretuesi i kartelave kontrolluese, loaderi i nevojshëm për
vendosjen e programeve sistemore dhe aplikative në memorie dhe drajverët e njësive të
nevojshëm për kryerjen e operacioneve hyrëse-dalëse.
1.4 Performansat
Kompjuterët, posaqërisht ata të mëdhej kanë qenë dhe janë makina të shtrenjta.
Shfrytëzimi sa më efektiv është kërkesë esenciale. Kalimi në përpunimin grupor (ang. batch
processing) ka përmirësuar performansat e sistemeve të tilla. Sekuencimi automatik në anën tjetër
ka eliminuar shumë punë të nevojshme që kryheshin me dorë.
Mirëpo edhe këto nuk rritën në masën e dëshiruar kohën e shfrytëzimit të njësisë
qendrore. Arsye e kësaj ishte disproporcioni i theksuar i shpejtësive të punës së njësive të
ndryshme hyrëse-dalëse dhe njësisë qendrore. Derisa lexuesi i shpejtë i kartelave mund të lexonte
1200 kartela në minut, kompajleri ose asembleri ishte edhe në atë kohë të hershme në gjendje të
procesojë 300 kartela në sekond. Për program prej 1200 kartelash shfrytëzimi i njësisë qendrore
do të zgjatte 4 sekonda, e vetëm leximi 60 sekonda. Ky raport jep shfrytëzim të njësisë qendrore
prej vetëm 6.7% të kohës së shpenzuar. Problemi është se gjatë operacionit hyrës-dalës njësia
qendrore mbetet pa punë, duke pritur përfundimin e tij.
5
speciale të afta të bëjnë këtë bartje, ose për këtë punë angazhohej kompjuteri me mundësi më
modeste i specializuar për këtë punë. Ky lloj i përpunimit të të dhënave i njohur edhe si
përpunim satelitor (për shkak se kompjuteri i vogël ishte satelit i kompjuterit të madh) ishte
rasti i parë i përdorimit të dy ose më shumë kompjuterëve në kryerjen e punës së përbashkët.
Për të kaluar nga mënyra direkte ose on-line e punës në mënyrën off-line nuk ishte e
nevojshme të ndërrohet asnjë rrjesht në aplikacionin e shfrytëzuesit. Kur programi kishte nevojë
të lexonte ndonjë të dhënë hyrëse ai e thirrte të njejtën rutinë sistemore. Por në këtë rast kodi i
kësaj rutine nuk ishte kodi i drajverit të lexuesit të kartelave por kodi i drajverit të shiritit
magnetik.
Mundësia që programi të ekzekutohet me njësi të ndryshme hyrëse dalëse shkaktoi që tani
programet të mund t'i drejtohen njësive logjike. Sistemit operativ i mbeti detyrë që të përcaktojë
se cilën njësi fizike programi me të vërtetë do ta shfrytëzojë në momentin kur duhet të kryej
operacionet hyrëse-dalëse. Pasqyrimin e të dhënave nga njësitë logjike në njësi të vërteta e
kontrollonin kartelat kontrolluese ose komandat tjera.
Puna off-line mundësoi që në një sistem njëkohësisht të shfrytëzohen më shumë lexues të
kartelave dhe më shumë shtypës, të cilët siguronin të dhëna të mjaftueshme që sistemi të jetë tërë
kohën i zënë me punë.
Fig.1.3 Puna on-line (a) dhe off line (b) e njësive hyrëse - dalëse
1.6 Baferimi
6
Shënimi (ang. record) është njësia natyrore e të dhënave. Shënimi ose recordi mund të
jetë fizik (blloku nga shiriti magnetik ose disku, karakteri nga tastiera etj.) ose logjik (p.sh. emri,
ndonjë numër, vektorë etj.). Shenimi logjik është i definuar nga aplikacioni; shënimi fizik është i
definuar nga karakteristikat e njësisë hytëse-dalëse. Bllokimi dhe çbllokimi programorë bëjnë
konvertimin e shenimeve logjike të aplikacionit në shenime fizike në njësinë hyrëse-dalëse.
Shenimi ose recordi është njësi e të dhënave që shfrytëzohet për baferim.
Baferimi i mbanë njësitë hyrëse-dalëse dhe njësinë qendrore të zëna me punë. Nëse njësia
qendrore e kryen e para punën atëherë ajo do të pret që shënimi i ardhshëm të lexohet nga njësia
hyrëse-dalëse. Kjo pritje nuk do të duhet të jetë e gjatë dhe është gjithnjë më e shkurtë se kur
baferimi nuk zbatohet. Nëse njësia hyrëse-dalëse e kryen e para punën ajo mund të vazhdojë ose
të ndërprejë përkohësisht punën. Nëse njësia hyrëse-dalëse vazhdon punën të dhënat do të
vendosen në bafer. Baferi do të përmbajë të dhëna të cilat janë lexuar por nuk janë përpunuar nga
njësia qendrore, ose të dhënat të cilat janë përpunuar por nuk janë dërgu në njësinë dalëse.
Kapaciteti i këtyre baferëve varet nga njësia hyrëse-dalëse. Vlerat karakteristike janë prej 128 deri
4096 bajt.
Implementimi i baferimit (shkruarja e programit që do të kontrollojë buferimin) nuk është
problem i lehtë. Për të evituar problemin e detektimit të përfundimit të operacionit të hyrje-daljes
shfrytëzohen ndërprerjet. Në mommentin e kryerjes së operacionit njësia hyrëse-dalëse do të
lajmërojë njësinë qendrore, e cila më vonë do të kryej të gjitha veprimet e nevojshme.
Duhet thënë se baferimi është ngushtë i lidhur me përpunimin e ndërprerjeve. Ky fakt si
dhe vështirësia që të shkruhen programet pa gabime për kontrollin e baferimit na çojnë në
konkludim se këtë problem nuk duhet lënë në përgjegjësi të programerit të aplikacionit por duhet
lënë në kompetencë të sistemit operativ. Çdo monitor rezident ose drajver i njësisë harëse-dalëse
përmbajnë baferët sistemorë hyrës-dalës, për secilën njësi hyrëse-dalëse. Kur aplikacioni të
kërkojë kryerjen e hyrje-daljes zakonisht do të shkaktojë vetëm transferin e të dhënave nga njëri
në tjetrin bafer sistemor. Operacioni aktual hyrës dalës do të jetë ose i kryer më parë ose do të
kryhet më vonë kur njësia të jetë në dispozicion.
Baferimi zbut variacionet në kohën e nevojshme për përpunimin e shënimit. Nëse
shpejtësitë mesatare (në rekord për sekond) të njësisë qendrore dhe njësisë dalëse janë
përafërsisht të njejta baferimi mundëson që njësia qendrore të jetë pak përpara ose pak pas njësisë
hyrëse dalëse duke mundësuar punën e dyjave me shpejtësi të plotë.
Mirëpo, pasi njësia qendrore është gjithnjë më e shpejtë se njësitë hyrëse-dalëse atëherë
njësia qendrore gjithnjë do të gjejë bafer të zbrazët dhe do të duhet të presë njësinë hyrëse. Gjatë
daljes së të dhënave njësia qendrore do të punojë pa ndërprerje derisa të mbushen të gjithë
baferët, e pastaj do të pret njësinë dalëse. Pra, nëse aplikacioni është kryesisht i orientuar në hyrje-
dalje të të dhënave, d.m.th. kur numri i operacioneve të hyrje-daljes është shumë më i madh se i
operacioneve të llogaritjes, shpejtësia e përpunimit do të varet nga shpejtësia e njësisë hyrëse-
dalëse. Në rastin e kundërt kur aplikacioni është i orientuar më shumë kah njësia qendrore e më
pak kah operacionet hyrëse-dalëse, atëherë baferët hyrës do të jenë gjithnjë të mbushur, ndërsa
bafferët dalës do të jenë gjithnjë të zbrazët. Në këtë rast njësia qendrore nuk do të mund të
përcjellë njësitë hyrëse-dalëse.
Baferimi ndihmon të zbuten problemet e performansave jo të njejta të komponenteve të
kompjuterit, por zakonisht nuk është i mjaftueshëm.
1.7 Spulingu
7
kalojnë prej një pjese të diskut në tjetrën u bë e mundur që të dhënat në një pjesë të diskut të
shkruhen derisa nga pjesa e tjetër e tij të lexohen.
Përmbajtja e kartelave me vrima tani bartej direkt në disk. Vendi i shembëlltyrës së secilës
kartelë tani mbahet në tabelë të posaçme në disk. Kur aplikacioni ka nevojë të lexojë ndonjë
kartelë ai në fakt e lexon përmbajtjken e cila ndodhet në disk. Ngjashëm kur aplikacioni e kërkon
printerin për të shtypur një rrjesht, përmbajtja që duhet të shtypet shkruhet në baferin sistemor,
ndërsa shtypja bëhet pas kryerjes së aplkacionit.
Kjo formë e procesimit quhet spuling (ang spooling, Simultaneous Peripheral Operation
On-Line). Spulingu në fakt e shfrytëzon diskun si bafer shumë të madh për lexim të sa më shumë
të dhënave që është e mundur nga njësitë hyrëse dhe për vendosje të datotekave dalëse deri kur
njësitë dalëse të jenë në gjendje t'i pranojnë.
Fig.1.4 Spulingu
1.8 Multiprogramimi
Puna off-line, baferimi dhe spulingu i kanë kufizimet e veta. Në rastin e përgjithshëm një
shfrytëzues nuk mundet që tërë kohën ta angazhojë njësinë qendrore. Multiprogramimi është
8
tentim që të rritet shfrytëzimi i njësisë qendrore ashtu që njësia qendrore të jetë gjithnjë e zënë me
ndonjë përpunim.
Ideja e multiprogramimit është që nga grupi i punëve (ang. job pool) në kompjuterë të
zgjedhet njëri që do të ekzekutohet. Kjo punë pas një kohe të kaluar në llogaritje do të ketë
nevojë të kryej operacionet e hyrjes ose daljes së të dhënave. Në sistemin njëprogramorë njësia
qendrore do të duhej të priste derisa ky operacion të kryej. Në sistemin multiprogramorë njësia
qendrore do të kalonte në ekzekutimin e punës tjetër. Kur më vonë kjo punë do të ketë nevojë të
kryej ndonjë operacion të hyrje-daljes, njësia qendrore do të kalojë në ekzekutimin e ndonjë pune
tjetër. Më vonë, është e mundur që aplikacioni i parë i përmendur, me të kryer të operacionit të
hyrje-daljes, të vazhdojë ekzekutimin e vet. Në këtë mënyrë derisa në sistem te ketë ndonjë punë
për tu kryer njësia qendrore nuk do të rrijë e pa punë.
9
1.9 Time sharing sistemet
10
Fig.1.6 Tipet e sistemeve operative
Sot shumica e sistemeve operative kanë mundësi edhe të beç përpunimit edhe të time
sharingut, edhepse koncepti bazik dhe mënyra e shfrytëzimit mund të jetë e orientuar më shumë
në njërën ose tjetrën kahje.
Kur kompjuteri shërben për kontrollin e rrjedhës së ndonjë procesi teknologjik, është e
nevojshme që ai të reagojë në suaza të kohës së kufizuar dhe të definuar me natyrën e
aplikacionit. Nëse kjo kohë tejkalohet aksioni i kompjuterit s'ka kuptim e mund të shkaktojë edhe
ndonjë efekt të dëmshëm. Kjo kohë quhet kohë reale. Përpunimi i kryer brenda intervalit të tillë
kohor quhet përpunim në kohë reale. Te sistemet operative të kohës reale është e
domosdoshme që përpunimi (në shumicën e rasteve kjo është reagimi në ndonjë vlerë të dhënë
nga ndonjë senzor) të kryhet brenda këtij intervali, përndryshe i tërë sistemi do të bie.
1.11 Mbrojtja
Sistemet e para kompjuterike ishin sisteme të një shfrytëzuesi. Ky kishte kontrollin mbi
tërë kompjuterin. Me zhvillimin e sistemeve operative shumë nga këto funksione kaluan në
kompetencë të tij, posaçërisht operacionet e hyrje-daljes.
Me qëllim të shfrytëzimit më të mirë të njësisë qendrore sistemet operative mundësuan
shfrytëzimin e resurseve të kompjuterit nga ana e më shumë programeve njëkohësisht. Spulingu
dhe multiprogramimi ishin mënyra se si realizohej kjo mënyrë e punës.
Mirëpo përveç rritjes së shkallës së efikasitetit të njësisë qendrore, këto sisteme operative
paraqitën edhe disa probleme. Kur kompjuteri angazhohej nga një shfrytëzues gabimi eventual në
program mund të ndikonte vetëm në rrjedhën e atij programi. Me ndarjen e resurseve mes më
shumë shfrytëzuesve gabimi i paraqitur në njërin program mund të çrregullonte punën e
programeve tjera e edhe të vet sistemit operativ. Sistemi operativ i koncipuar si duhet duhet të
ofrojë mbrojtje nga programet që kanë gabime, dhe të sigurojë që rrjedha e programeve tjera në
11
sistem të mos ndikohet nga programet e tilla.
Shumë nga gabimet e programeve i detekton hardveri i kompjuterit. Gabimi i detektuar
shkakton gjenerimin e ndërprerjes softverike (ang. trap) që shkakton që kontrollin ta merr
monitori rezident (sistemi operativ). Pasi ta ruajë gjendjen e programit të ndërprerë dhe të paraqet
porosinë për gabimin e detektuar, sistemi operativ do të aktivizojë ndonjë program tjetër.
Mbrojtja është e nevojshme për të gjitha resurset e kompjuterit që përdoren nga
programet që ekzekutohen. Pra nevojitet mbrojtja e hyrje-daljes, mbrojtja e memories dhe
mbrojtja e njësisë qendrore.
Nëse programi i shfrytëzuesit do të tentojë t'i lexojë të dhënat të cilat ndodhen në vazhdim
të të dhënave të tij duhet gjetur mënyrë që kjo të mos lejohet. Një mënyrë e pengimit të kësaj
është të shfrytëzohet drajveri i njësisë për të kryer operacionin e tillë. Drajveri i njësisë duhet të
ketë mundësi që të detektojë fundin e të dhënave të një programi dhe fillimin e të dhënave të
programit tjetër. Ky nënprogram ka mundësi të detektimit të paraqitjes së kartelave kontrolluese
të cilat ndajnë njërin program nga tjetri. Në rast të tentimit të leximit të kartelës kontrolluese
drajveri i njësisë do t'ia kthej kontrollin monitorit rezident i cili pastaj do të kryej veprimin e
nevojshëm.
Kjo procedurë do të sigurojë rrjedhën normale të punëve në kompjuterë, përveç në rastin
kur shfrytëzuesi vendos që mos ta shfrytëzojë drajverin e njësisë. Thënë ndryshe, shfrytëzuesi
mund të vendosë që me qëllim të eksperimentimit ose pse konsideron se drajveri i njësisë nuk
është i shkruar sipas shijes së tij ose për ndonjë arsye tjetër të shkruaj vetë drajverin që do të
kontrollojë operacionet e hyrje-daljes me njësinë në fjalë.
Këtë mundësi sistemi operativ nuk guxon ta lejojë me qëllim të sigurimit të punës së
rregullt të krejt sistemit kompjuterik. Për të realizuar këtë ne duhet të sigurojmë që kompjuteri t'ia
lejojë sistemit operativ leximin e kartelave kontrolluese, ndërsa shfrytëzuesve t'ia bëjë këtë të
pamundur. Në fakt dëshirohet që kompjuteri të sillet ndryshe për sistemin operativ e ndryshe për
programet e shfrytëzuesve. Kjo nënkupton ekzistimin e dy modeve të punës së kompjuterit,
modin e shfrytëzuesit dhe modin e sistemit (supervizorit, mbikëqyrësit, monitorit). Që kjo të
realizohet duhet që në hardver të ekzistojë një bit indikatorë që tregon modin e punës momentale
të kompjuterit.
Hapi i ardhshëm është që të gjitha instruksionet për kryerjen e operacioneve të hyrje-
daljes t'i definojmë si instruksione të privilegjuara. Instruksionet e tilla mund të ekzekutohen
vetëm kur kompjuteri punon në modin sistemor. Tentimi i ekzekutimit të instruksionit të tillë nga
modi i shfrytëzuesit do të shkaktojë gjenerimin e trepit, ndërprerjen e ekzekutimit të programit të
shfrytëzuesit dhe kalimin e kontrollit në duar të sistemit operativ. Çdo herë që paraqitet trepi ose
ndërprerja kontrolli i jepet sistemit operativ. Gjithmonë para se të kalojë në ekzekutimin e
programit të shfrytëzuesit kompjuteri do të kalojë në modin e shfrytëzuesit.
12
Fig.1.7 Përdorimi i thirrjes sistemore për realizimin e hyrje-daljes
Modi dual i punës na siguron që vetëm drajverët e njësive, që janë pjesë e sistemit
operativ mund të lexojnë kartelat kontrolluese. Programi i shfrytëzuesit nuk mundet që kartelat
kontroluuese t'i lexojë dhe t'i trajtojë si të dhëna te veta.
Puna e kompjuteri tani bëhet zakonisht duke kaluar këto hapa. Kur të startohet,
kompjuteri është në modin sistemor. Pas leximit të kartelave kontrolluese, në memorien operative
sjellet programi që dëshirojmë të ekzekutohet. Para se të fillojë ekzekutimi i programit të lexuar,
sistemi operativ e bjen kompjuterin në modin e shfrytëzuesit dhe kontrollin mbi kompjuter ia
dorëzon programit të shfyrtëzuesit. Me të përfunduar të ekzekutimit të programit, kontrolli i
dorëzohet prap sistemit operativ. Programi i shfrytëzuesit nuk mund të ekzekutojë direkt
instruksionet e hyrje-daljes, për arsye se instruksionet e tilla mund të kryhen vetëm në modin
sistemor.
Pasi operacionet e hyrje daljes mund t'i kryej vetëm sistemi operativ, programi i
shfrytëzuesit duhet të kërkoj nga sistemi operativ që të kryej operacionet hyrëse-dalëse për te.
Shumica e kompjuterëve e kanë në repertorin e vet të instruksioneve, instruksionin e quajtur
thirrje sistemore (ang. system call ose monitor call). Kur të ekzekutohet instruksioni i tillë ai
trajtohet nga hardveri si ndërprerje softverike. Përmes vektorit të ndërprerjes kontrolli i dorëzohet
rutinës që është pjesë e sistemit operativ ose monitorit. Biti indikator i modit të punës kalon në
gjendjen e cila tregon se kompjuteri është në modin e sistemit. Sistemi operativ e kryen
operacionin e definuar me parametrat e thirrjes sistemore dhe pasi ta ketë bartur kompjuterin në
modin e shfrytëzuesit vazhdon punën duke ekzekutuar instruksionin i cili vjen pas thirrjes
sistemore.
13
1.11.2 Mbojtja e memories
14
Fig.1.8 Mbrojtja hardverike e adresave të monitorit rezident
15
1.11.3 Mbrojtja e njësisë qendrore
16
2. Shërbimet e sistemit operativ
Shërbimet që do t'i ofron një sistem operativ do të ndryshojnë në një masë nga shërbimet
që do t'i ofrojë ndonjë sistem tjetër operativ. Mirëpo ekziston një numër i shërbimeve të cilat
mund të gjinden në secilin sistem operativ. Këto funksione të sistemit operativ ofrojnë lehtësime
programerit dhe e bëjnë detyrën e tij më të lehtë.
Ekzekutimi i programeve. Shfrytëzuesit duhet të ekzekutojnë programet e tyre. Sistemi
operativ duhet të jetë në gjendje që programin e shfrytëzuesit ta vendosë në memorie dhe ta
ekzekutojë. Programi duhet të jetë në gjendje të përfundojë ekzekutimin e vet qoftë në mënyrë
normale qoftë jonormale.
Operacionet hyrëse-dalëse. Programi që ekzekutohet mund të kërkojë ekzekutimin e
operacioneve hyrëse-dalëse. Këto operacione kanë të bëjnë me njësi ose datoteka. Për njësi të
ndryshme mund të nevojiten funksione të ndryshme. Të gjitha këto duhet t'i sigurojë sistemi
operativ, pasi shfrytëzuesi nuk ka mundësi që këto t'i kryej vetë.
Manipulimet me datoteka. Sistemi i datotekave është me rëndësi të veçantë. Programet
aplikative kanë nevojë të manipulojnë me datoteka, t'i krijojnë, të shkruajnë në to, t'i fshijnë etj.
Detektimi i gabimeve. Sistemi operativ duhet gjithmonë të jetë i gatshëm të reagojë në
gabime. Gabimet mund të shfaqen në pjesë të ndryshme të kompjuterit, në njësinë qendrore, në
njësitë hyrëse-dalëse, në memorie. Programet e shfrytëzuesve munden poashtu të kenë gabime.
Për çdo lloj të gabimit sistemi operativ duhet të jetë në gjendje të kryej operacionet e nevojshme
për vazhdimin e punës.
Përveç këtyre funksioneve për sigurimin e punës efikase të sistemit operativ ekziston edhe
një numër i funksioneve të dedikuara kryesisht nevojave të vet sistemit operativ.
Ndarja e resurseve. Kur në sistem ekzistojnë më shumë shfrytëzues ose më shumë punë
që ekzekutohen njëkohësisht, paraqitet nevoja që atyre tu ndahen resurset e sistemit. Programet
për kontrollin e këtyre punëve janë pjesë e sistemit operativ.
Evidencat. Shpesh është e nevojshme që të mbahet evidenca për shfrytëzimin e resurseve
të ndryshme nga ana e shfrytëzuesve dhe aplikacioneve. Kjo bëhet për nevoja të përcjelljes së
punës së shfrytëzuesve dhe eventualisht për pagesën e shërbimeve të kryera si dhe për mbajtjen e
statistikave që kanë për qëllim përmirësimin e shfrytëzimit të sistemit operativ.
Mbrojta. Për shkak se në sistemin kompjuterik mund të ekzekutohen punë të ndryshme
njëkohësisht është e nevojshme që sistemi operativ të ofrojë mbrojtje të dhënave dhe programeve
nga interferencat e padëshirueshme.
17
2.2.1 Thirrjet sistemore
Manipulimi me datoteka
Shfrytëzuesi duhet të jetë në gjendje që të krijojë dhe t'i fshijë datotekat. Për të bërë këtë
ai përdorë thirrjet sistemore create file dhe delete file. Thirrjet e tilla programore kërkojnë emrin
e datotekës që krijohet ose fshihet e ndonjëherë edhe ndonjë atribut të saj. Datotekën e krijuar
18
duhet të kemi mundësi ta hapim (thirrja sistemore open), të lexojmë nga ajo (read) dhe të
shkruajmë në te (write). Ndonjëherë është e nevojshme që të pozicionohemi në kuadër të
datotekës, në fillim ose në fund të saj (reposition). Në fund, datotekën duhet mbyllur, duke ia
bërë me dije në atë rast sistemit operativ se nuk e shfrytëzojmë më. Këtë e bëjmë me thirrjen
sistemore close.
Të njejtat operacione duhet kryer edhe mbi direktoriume. Poashtu, si për datoteka, ashtu
edhe për direktoriume na nevojitet të dijmë ose të vendosim atributet e tyre. Për këtë përdorim
thirrjet sistemore get file attributes dhe set file attributes.
Udhëheqja e njësive
Mirëmbajtja e informatave
Shumë thirrje sistemore ekzistojnë vetëm për të përcjellë informata mes programit të
shfrytëzuesit dhe sistemit operativ. Shumica e sistemeve operative e kanë thirrjen sistemore për
dhënjen e kohës (time) dhe datës (date) sistemore. Thirrjet tjera sistemore japin informatat për
numrin momental të shfrytëzuesve, verzionin e sistemit operativ, memorien e lirë, hapësirën e lirë
në disk, etj.
19
Fig.2.1 Bartja e parametrave si tabelë
20
të sigurohen edhe ndamas nga sistemi operativ.
Vendosja e programeve në memorie dhe ekzekutimi. Programin e kompajluar ose
asembluar duhet ta vendosim në memorie nëse kemi ndërmend ta ekzekutojmë. Sistemi operativ
për kryerjen e këtyre punëve përmban programet sistemore të njohura si: louderë absolut (ang.
absolute loader), louderë relokatibil (ang. relocatable loader), editorë lidhës (ang. linkage
editors), dhe louderë mbulues (ang. overlay loaders). Për kontrollin, detektimin dhe korigjimin e
programeve ekzistojnë programe sistemore të quajtur dibagerë (ang. debugger).
Programi më i rëndësishëm sistemor i sistemit operativ është komand interpreteri.
Komand interpreteri është ai program që ekzekutohet dhe me të cilin komunikon shfrytëzuesi sa
herë që dëshiron të jep ndonjë urdhër sistemit operativ. Kur të startohet aplikacioni i ri ose kur
shfrytëzuesi ti paraqitet sistemit, automatikisht ekzekutohet programi i cili i lexon dhe interpreton
komandat. Ky program quhet edhe interpreter i kartelave kontrolluese, interpreter i linjës
komanduese (ang. command line interpreter), procesorë i komandave të konzolës (ang.
console command processor; konzola, zakonisht terminali kryesor i sistemit kompjuterik) ose
guaskë e sistemit operativ (ang. shell, shq. guaska). Funksioni i këtij programi është i thjeshtë:
të pranojë komandën dhe ta ekzekutojë.
Shumë nga komandat e këtij niveli kanë të bëjnë me datoteka. Ka dy mënyra se si këto
komanda janë të implementuara. Në rastin e parë komand interpreteri përmban kodin për
ekzekutimin e komandës. Për shembull, komanda për fshirjen e një datoteke do të shkaktonte që
komand interpreteri të kërcejë në atë pjesë të kodit të tij që vendos parametrat dhe bënë thirrjen e
duhur sistemore. Në këtë rast numri i komandave që mund të jepen cakton madhësinë e komand
interpreterit, pasiqë çdo komandë e kërkon kodin e saj implementues.
Mënyrë tjetër e realizimit të funksionit të komand interpreterit është implementimi i
komandave në formë të programeve sistemore. Në këtë rast, komand interpreteri nuk e di se çka
duhet bërë komanda e dhënë, ai në fakt as nuk e përmban kodin për ekzekutimin e saj. Ai vetëm e
shfrytëzon komandën që të identifikojë datotekën që do ta vendosë në memorie dhe e cila në fakt
do ta kryej operacionin e kërkuar nga komanda e dhënë. Nëse dëshirojmë ta fshijmë datotekën A,
atëherë komanda që mund të jetë e formës
delete A
Ato çka shfrytëzuesi sheh prej sistemit operativ është kryesisht e definuar nga programet
sistemore, posaçërisht nga komand interpreteri. Programeri i sistemit operativ ka një shikim krejt
tjetër të sistemit operativ. Ai duhet të mendojë se cilat resurse fizike do të përdoren dhe në çfarë
mënyre do të përdoren për të realizuar kërkesën e dhënë të shfrytëzuesit.
21
Sistemet operative janë programe të udhëhequra nga ngjarjet në kompjuter. Nëse nuk ka
program që duhet ekzekutuar, ose njësi hyrëse-dalëse që duhet shërbyer, ose shfrytëzues në
kërkesë të së cilit duhet dhënë përgjegje, sistemi operativ nuk do të bëjë asgjë. Ngjarjet në
kompjuter janë gati gjithmonë të sinjalizuara nga ndërprerja ose trepi. Mund të thuhet se sistemi
operativ është i udhëhequr nga ndërprerjet.
Struktura e përgjithshme e sistemit operativ është e definuar nga kjo mënyrë e punës së
sistemit operativ. Nëse ndodh ndërprerja ose trepi, hardveri i kompjuterit ia dorëzon kontrollin
mbi kompjuter sistemit operativ. Pasi ta ketë ruajtur gjendjen e regjistrave relevant për vazhdimin
e programit, sistemi operativ përcakton se cili është shkaku i ndërprerjes. Kjo mund të bëhet me
thirrje të njësive të cilat mund të shkaktojnë ndërprerjen ose mund të caktohet në bazë të vektorit
të ndërprerjes. Mund të paraqiten disa lloje të ndërprerjeve. Këto janë:
Thirrja sistemore,
Ndërprerja e njësisë hyrëse-dalëse,
Gabimi i programit.
Për çdo lloj të ndërprerjes, në sistemin operativ ekziston kodi që përcakton se çfarë
veprimesh duhet kryer.
Shumica e ngjarjeve të cilat duhet ti kontrollojë sistemi operativ janë ndërprerjet e njësive
për hyrje-dalje. Kjo ngjarje do të paraqitet si rezultat i thirrjes sistemore nga ana e shfrytëzuesit
me të cilën kërkohet hyrja-dalja e të dhënave. Pasi të ketë startuar hyrja ose dalja e të dhënave,
22
paraqiten dy mundësi të vazhdimit të punës së kompjuterit. Zgjidhje më e thjeshtë është të presim
derisa operacioni i dëshiruar të përfundohet. Zgjidhje alternative është që menjëherë pas fillimit të
operacionit të hyrje-daljes, t'ia kthejmë kontrollin programit të shfrytëzuesit pa pritur përfundimin
e operacionit të inicuar.
Pritja e përfundimit të operacionit të hyrjes ose daljes së të dhënave mund të realizohet
përmes ekzekutimit të instruksionit për pritje (ang. wait). Te kompjuterët që nuk e kanë këtë ins
truksion pritja e përfundimit të hyrje-daljes mund të realizohet me ekzekutimin e unazës për pritje,
të formës:
23
ndërprerja sinjalizon përfundimin e kërkesës për hyrje-dalje. Nëse për atë njësi ekzistojnë kërkesa
tjera do të vazhdojmë me përpunimin e kërkesës së ardhshme.
Me të kryer të përpunimit të ndërprerjes, nëse në tabelën e gjendjes së njësive, kemi
informatën se një program është duke pritur përfundimin e këtij operacioni, kontrolli do ti
dorëzohet atij. Përndryshe, do ti kthehemi asaj pune që kemi qenë duke bërë në momentin e
paraqitjes së ndërprerjes.
Te sistemet interaktive është shpesh e lejuar që shfrytëzuesi të shkruaj në tastierë para se
t'i jetë dorëzuar kontrolli mbi sistem. Në këtë rast mund të paraqitet ndërprerja, që tregon se nga
terminali kanë arritur karakterët. Në të njejtën kohë, në tabelën e gjendjes së njësive, kemi
informatën se asnjë program nuk ka kërkuar hyrjen nga terminali. Nëse shkruarja paraprake e
karakterëve në tastierë është e lejuar, duhet të ekzistojë baferi që do ti ruajë këta karakterë derisa
ndonjë program ti kërkojë. Për çdo terminal nevojitet nga një bafer.
Ndërprerjet që i gjeneron tajmeri mund të përdoren për llogaritjen e kohës së kaluar nga
ndonjë moment inicial. Nëse ndërprerjet paraqiten çdo sekond, atëherë nëse kemi pasë 420
ndërprerje prej momentit kur kompjuterit i është thënë se ora është 12:00:00, kompjuteri do të na
tregojë se tani është ora 12:07:00.
Ndërprerjet e tajmerit poashtu shfrytëzohen që të pamundsohet që ndonjë program ta
keqpërdorë kohën e njësisë qendrore dhe me zgjatje të pakontrolluar, të bllokojë rrjedhën e
programeve tjera. Zakonisht, secilit program i jepet intervali kohor sa do të ekzekutohet. Ky
interval jepet në formë të numrit të ndërprerjeve të tajmerit. Me çdo ndërprerje që paraqitet
sistemi operativ starton rutinën e shkurtë e cila dekrementon këtë numër dhe nëse vlera e tij është
pozitive ia kthen përsëri kontrollin programit. Në momentin kur ky numër bëhet negativ,
ekzekutimi i programit kryhet për shkak të tejkalimit të kufirit kohor.
Në figurën e paraqitur është dhënë një skemë e mundshme e rrjedhës së punës së sistemit
operativ. Nga kjo skemë mund të identifikojmë disa pjesë të përbashkëta për të gjitha sistemet
operative. Këto janë drajverët e njësive, përpunuesi i ndërprerjeve (ang. interrupt handler),
tërësia e rutinave të thirrjeve sistemore dhe komand interpreteri. Pjesë e rëndësishme e
sistemit operativ është edhe sistemi i datotekave.
24
Fig.2.3 Rrjedha e përgjithshme e sistemit operativ
25
3. Sistemet e datotekave
Informatat që ndodhen në datotekë janë të definuara nga krijuesi i saj. Datoteka mund të
përmbajë program burimor, objekt program, të dhëna numerike, tekst etj. Varësisht se çfarë
informatash ruan, datoteka ka strukturë të brendshme të ndryshme. Tekst datoteka është varg i
simboleve të organizuar në rrjeshta dhe faqe, programi burimor është varg i procedurave dhe
funksioneve, objekt datoteka është varg i fjalëve të organizuara në blloqe të rekordeve të loaderit,
etj.
Njëri nga problemet që parashtrohet këtu është se sa duhet sistemi operativ të jetë i
njohur me strukturën e datotekave. Kur sistemi operativ e di strukturën e datotekës ai është në
gjendje të ofrojë shërbime të ndryshme.
Për shembull, të marrim rastin kur shfrytëzuesi tenton të shtyp objekt programin. Ky
tentim zakonisht jep si rezultat një varg simbolesh të pakuptimta. Nëse sistemi operativ do të ketë
dijeni mbi strukturën e datotekës ai do të mund të ndalonte shtypjen e një programi të tillë dhe do
të shpëtonte shfrytëzuesin nga mundi i panevojshëm.
Më tutje, kemi rastin kur sistemi operativ përcjellë datën e krijimit të datotekës që
përmban programin burimor dhe datën e krijimit të datotekës që përmban formën ekzekutive të
programit të tillë. Tentimi i ekzekutimit të programit që e ka datën e krijimit më të hershme se
versioni burimor i tij, rezulton në kompajlimin dhe linkimin automatik të programit burimor. Që
sistemi operativ të mund të kryej këtë funksion, ai duhet të jetë në gjendje që të bëjë identifikimin
e tipit të datotekave, të krahasojë kohën e krijimit të tyre dhe të përcaktojë gjuhën programore në
të cilën është shkruar programi burimor.
Aftësia e sistemit operativ që të njohë strukturën e brendshme të datotekave shkakton që
madhësia e sistemit operativ të rritet. Për çdo tip të datotekave sistemi operativ duhet të përmbajë
26
kodin që bënë identifikimin e datotekës dhe përkrah operacionet për këtë tip të datotekave.
Problem i posaçëm është në rastin kur aplikacioni i krijuar kërkon që informatat në datotekë të
organizohen në mënyrë që nuk është e përkrahur nga sistemi operativ.
Rasti i kundërt është me sistemet operative që nuk dallojnë tipet e ndryshme të
datotekave. Këto sisteme operative ofrojnë fleksibilitet maksimal, por në anën tjetër nuk ofrojnë
kurfarrë përkrahjeje. Është detyrë e shfrytëzuesit të sistemit operativ që aplikacionet e krijuara të
përmbajnë kodin që do të përshtatë datotekën hyrëse strukturës gjegjëse. Sistem i tillë operativ
është sistemi UNIX.
Sistemet e para të datotekave kanë qenë të bazuara në shirita magnetik. Çdo datotekë
është mapuar në shiritin e saj magnetik. Mirëpo, pasi këta shirita kanë qenë të kapacitetit që
tejkalonte dukshëm madhësinë e datotekave të zakonshme, është paraqitë problemi i shfrytëzimit
joracional të tyre. Në anën tjetër kemi rastin e datotekave shumë të mëdha të cilat nuk mund të
vendosen në një shirit.
Për të zgjedhur problemin e vendosjes së datotekave të vogla në shirita me kapacitet të
madh, janë realizuar sistemet që mundësojnë vendosjen e më shumë datotekave në një shirit. Kjo
ka pasë si pasojë nevojën e ekzistimit të një liste që do të tregojë se cilat datoteka në cilin shirit
ndodhen. Këtë listë do ta quajmë direktorium. Nga prodhuesi i njohur IBM për një shirit
magnetik ka mbetur emërtimi vëllim, emërtim që më vonë do të zgjerohet edhe në disqe. Çdo
vëllim e ka direktoriumin në të cilin janë emrat dhe informatat për datotekat që ndodhen në te.
Gjetja e datotekës ka të bëjë me identifikimin e shiritit që përmban datotekën (zakonisht
punë e bërë nga shfrytëzuesi), kërkimin e direktoriumit dhe pozicionimin e shiritit te datoteka e
kërkuar. Leximi mbetet i njejtë si te shiritat që përmbanin vetëm një datotekë. Te këta shirita
fundi i datotekës dallohet nga fundi i shiritit. Poashtu duhet bërë dallim mes pozicionimit në
kuadër të datotekës dhe pozicionimit në kuadër të shiritit.
Problemet tjera me datoteka në shirit magnetik kanë të bëjnë me leximin e të dhënave
alternativisht nga dy datoteka në të njejtin shirit, me ndërrimet e bëra në ndonjërën prej tyre dhe
në rastin e shtimit të datotekës së re në fund të shiritit. Leximi alternativ i të dhënave nga dy
shirita shkakton mbështjellje alternative para dhe prapa të shiritit që shpenzon kohën e
kompjuterit. Modifikimi i njërës datotekë shkakton që e gjithë datoteka të rishkruhet e përveç
kësaj edhe të gjitha datotekat të vendosura pas saj në shirit. Në disa raste kur madhësia e
hapësirës ku do të vendoset direktoriumi është jofikse, modifikimin komplet të shiritit do të
shkaktojë edhe shtimi i datotekës në fund për arsye se ky shtim shkakton rritjen e hapësirës së
zënë nga direktoriumi që gjithmonë vendoset në fillim të shiritit.
27
Fig.3.1 Madhësia e datotekave në sistemin e datotekave
28
Të dhënat mes memories dhe disqeve barten në grupe të sektorëve. Adresimi i sektorit
kërkon njohjen e numrit të cilindrit (ose trekut), sipërfaqes dhe sektorit. Në këtë mënyrë disku
mund të trajtohet si fushë tridimenzionale. Zakonisht kjo hapësirë trajtohet nga sistemi operativ si
hapësirë njëdimenzionale e disk-blloqeve. Çdo bllok është sektor. Zakonisht adresat e blloqeve
rriten në kuadër të sektorëve të një trekut, duke vazhduar në trekët tjerë të të njejtin cilindër dhe
përfundimisht prej cilindrit 0 deri te cilindri i fundit i diskut. Nëse s është numri i sektorëve për
trek, t numri i trekëve për cilindër, atëherë mund të kalojmë nga sektori k i sipërfqes j i cilindrit i
në bllokun b sipas formulës:
b=k+s*(j+i*t)
Disqet kanë më shumë përparësi ndaj shiritave magnetik. Të dhënat në disk mund të
rishkruhen në të njejtin vend. Në disqe është e mundur që blloku të lexohet, modifikohet dhe
përsëri të shkruhet në disk në të njejtin vend. Leximi i të dhënave nga më shumë datoteka është
lehtësuar sepse koha e kërkimit dhe vonesës (e rendit më pak se 100 ms) është e vogël në
krahasim me shiritat magnetik.
Edhe disqet përmbajnë direktoriumin e njësisë (vëllimit), që tregon se cilat datoteka
ndodhen në disk. Direktoriumi përveç emrit përmban edhe të dhëna të tjera të përmendura më
lartë. Direktoriumi i çdo vëllimi ndodhen zakonisht në lokacion fiks. Kjo është posaçërisht e
përshtatshme për fllopi disqe ose disqe tjera jofikse (disqe që mund të barten prej njërës njësi në
tjetrën ose prej një kompjuteri në një tjetër). Përmbajtja e disqeve të tilla mund të lexohet pa
marrë parasysh njësinë në të cilën janë montuar.
3.1.4 Bllokimi
Disk sistemet e kanë zakonisht të definuar mirë madhësinë e bllokut që është i përcaktuar
nga madhësia e sektorit. Të gjitha operacionet hyrëse-dalëse të disqeve kryhen me shumëfisha të
blloqeve (rekordeve fizike) të cilët janë të njejtës madhësi. Shiritat magnetik lejojnë fleksibilitet
më të madh në definim të madhësisë së bllokut i cili mund të definohet edhe përmes programit.
Sidoqoftë, si te shiritat ashtu edhe te disqet, është rast i rrallë që madhësia e rekordit fizik
të jetë e njejtë me madhësinë e rekordit logjik. Përveç kësaj rekordët logjik mund të ndryshojnë
në madhësi. Për të zgjedhur këtë problem bëhet paketimi i rekordeve logjike në një rekord fizik.
Sistemi operativ UNIX definon datotekat si rrjedha (vargje) të bajtëve. Çdo bajt është i
adresueshëm përmes zhvendosjes nga fillimi i datotekës. Në këtë rast madhësia e rekordit logjik
është 1 bajt. Sistemi i datotekave automatikisht i paketon rekordet logjike 1 bajtëshe në rekorde
fizike (zakonisht 512 bajtëshe).
Nëse dijmë madhësinë e rekordit logjik, atij fizik dhe mënyrën e paketimit mund të
përcaktojmë se sa rekorde logjike ndodhen në një rekord fizik. Paketimin mund ta bëjë programi i
shfrytëzuesit ose sistemi operativ.
Datoteka mund të konsiderohet si varg (sekuencë) e blloqeve. Të gjitha operacionet
hyrëse-dalëse operojnë me bloqe. Konverzioni nga bloqet logjike në fizike është problem relati
visht i thjesht programor.
Si pasojë e përdorimit të blloqeve kemi paraqitjen e copëzimit të brendshëm (fragmentimit
intern). Të marrim rastin kur blloqet kanë madhësinë 512 bajt. Datotekës me madhësi 1845 bajta
do ti jepeshin 4 blloqe, madhësia e përbashket e të cilëve është 2048 bajtë. Siç mund të vërehet,
në bllokun e fundit, nga 512 janë shfrytëzuar vetëm 309 bajtë. Teprica prej 203 bajtëve mbetet e
humbur. Të gjitha sistemet e datotekave vuajnë nga fragmentimi intern. Blloqet më të mëdha
shkaktojnë shkallë më të lartë të fragmentimit intern.
29
3.1.5 Operacionet mbi datoteka
Datotekat mund të implementohen në njësi të ndryshme, shirita, disqe, disketa si dhe njësi
tjera më pak të zakonshme. Datoteka është entitet logjik që paraqet pjesë të emruar të
informatave. Datotekat mapohen ose implementohen në njësi të ndryshme fizike. Për të qenë në
gjendje të krahasojmë implementime të ndryshme të datotekave në njësi të ndryshme duhet të
kuptojmë definicionin e datotekës që është i pavarur nga implementimi. Datoteka është tip
abstrakt të dhënave. Për të definuar si duhet datotekën do të përmendim operacionet që mund të
kryhen mbi datoteka.
Koncepti i datotekës është i implementuar përmes sistemit operativ. Për t'i kryer
operacionet e përmenduar sistemi operativ ofron thirrjet sistemore për krijimin, shkruarjen,
leximin, pozicionimin dhe fshirjen e datotekës.
30
Shkruarja në datotekë. Që të shkruhet në datotekë, thirrja sistemore duhet të tregojë
emrin e datotekës dhe informatat që do të shkruhen në datotekë. Pasi ta ketë emrin e datotekës,
sistemi do të kërkojë direktoriumin që të gjejë pozitën ku ndodhet datoteka. Duke ditur adresën e
fundit të datotekës mund të llogaritet adresa e bllokut të ardhshëm dhe prej tij të vazhdojë
shkruarja e informatave të reja. Pasi të jetë kryer shkruarja, treguesi i shkruarjes në datotekë
duhet të azhurohet me vlerë të re që të mundësojë operacionet e ardhshme të shkruarjes.
Leximi i datotekës. Për të lexuar përmbajtjen e datotekës thirrja sistemore duhet të
specifikojë emrin e datotekës dhe të tregojë se në cilin lokacion në memorien operative duhet të
vendoset blloku i ardhshëm i datotekës. Si edhe te shkruarja, edhe këtu do të kërkohet
direktoriumi për t'u gjetur emri i datotekës dhe lidhur me të treguesi në bllokun që do të lexohet.
Pasi të jetë lexuar ky bllok, treguesi duhet të azhurohet. Në përgjithësi, datoteka mund të lexohet
ose në të mund të shkruhet. Lidhur me këtë datoteka mund të ketë dy tregues, njërin për lexim e
tjetrin për shkruarje. Në shumicën e rasteve sistemet operative kanë vetëm një tregues - treguesin
e pozitës momentale. Edhe operacioni i shkruarjes edhe ai i leximit e shfrytëzojnë të njejtin
tregues duke kursyer hapësirën në direktorium ku ruhet kjo informatë. Përdorimi i një treguesi të
tillë thjeshton edhe realizimin e sistemit operativ.
Pozicionimi i datotekës. Pozicionimi i datotekës në fillim nuk përfshin në fakt kurrfarë
operacioni hyrës-dalës. Me këtë rast do të kërkohet direktoriumi dhe vlera e treguesit të pozitës
momentale në datotekë do të resetohet në vlerën e cila tregon fillimin e datotekës.
Fshirja e datotekës. Që ta fshijë datotekën sistemi operativ do të kërkojë direktoriumin
dhe pasi ta ketë gjetur emrin e datotekës së kërkuar do të lirojë hapësirën e zënë në disk nga kjo
datotekë. Në fund do të fshihet emri i datotekës nga direktoriumi.
Mund të vërehet se të gjitha operacionet e përmendura përfshijnë në vehte kërkimin e
direktoriumit. Për të evituar këtë kërkim të shpeshtë shumë sisteme operative e hapin datotekën
vetëm atëherë kur ajo të jetë aktivisht e shfrytëzuar. Sistemi operativ me këtë rast e ruan në
memorien operative një tabelë të datotekave aktualisht të hapura. Çdo operacion hyrës dalës që
do të kërkohet të kryhet mbi datotekën do të kërkojë informatën e dëshiruar (pozita momemtale e
treguesit etj.) nga kjo tabelë e jo nga direktoriumi. Kur datoteka më nuk shfrytëzohet aktivisht ajo
do të mbyllet dhe do të fshihet nga tabela e datotekave të hapura.
Shumë sisteme në mënyrë implicite e hapin datotekën në momentin kur ti referohemi të
parën herë. Datoteka e hapur në këtë mënyrë do të mbyllet automatikisht me përfundimin e
programit që e ka inicuar hapjen e saj. Shumica e sistemeve operative kërkojnë që datoteka të
hapet në mënyrë eksplicite nga programeri me anë të thirrjes sistemore për hapjen e datotekës.
Thirrja sistemore për hapjen e datotekës do ta kërkojë direktoriumin dhe të gjitha të dhënat për
datotekën do t'i kopjojë në tabelën e datotekave të hapura. Për operacionet e hyrje-daljes do të
shfrytëzohet treguesi në pozitën e datotekës në tabelën e datotekave të hapura e jo emri i
datotekës, që eviton çdo kërkim të mëvonshëm.
31
Pozita momentale. Treguesi në pozitën momentale për lexim ose shkruarje në datotekë.
Mbrojtja. Të dhëna për kontroll të qasjes datotekës për lexim, shkruarje, ekzekutim etj.
Numruesi i shfrytëzimit. Treguesi i numrit të proceseve që momentalisht janë duke e
shfrytëzuar (e kanë hapur) datotekën.
Koha, data dhe identifikimi i procesit. Këto të dhëna mund të shfrytëzohen për
krijimin, ndryshimin e fundit dhe shfrytëzimin e fundit të datotekës. Përdoren për mbrojtje dhe
përcjellje të shfrytëzimit të datotekave.
HApësira që zënë këto të dhëna mund të shkojë prej 16 bajtë deri mbi 1000 bajtë për çdo
datotekë. Për sistemet me disa qindra ose disa mija datoteka madhësia e vetë direktoriumit mund
të jetë disa qindra ose mija bajtë. Për këtë arsye direktoriumi duhet të ruhet në njësi ndërsa në
memorie operative duhet të sjellen vetëm pjesë të tij sipas nevojës.
Direktoriumi mund të jetë i organizuar në mënyra të ndryshme. Organizimi i direktoriumit
duhet të mundësojë shtimin e datotekave të reja, fshirjen e datotekave, modifikimin e të dhënave
për datoteka, kërkimin e datotekave dhe listimin e të gjitha ose disa datotekave.
Direktoriumi i organizuar si listë lineare është lehtë të implementohet, por ka disa mangësi
posaçërisht në shpejtësi të punës. Problemi kryesor është kërkimi. Gjatë shtimit të datotekës së re
ose gjatë fshirjes së datotekës duhet të kontrollohet në mënyrë lineare i gjithë direktoriumi. Nëse
është fjala për datotekë të re ajo do të shtohet në fund të direktoriumit. Nëse është fjala për fshirje
duhet të lirohet hapësira në disk e zënë nga kjo datotekë. Nëse dëshirojmë ta shfrytëzojmë
hapësirën e liruar në direktorium pas fshirjes së datotekës, mundemi që hyrjen e përmendur në
direktorium ta markojmë si të lirë, ose që hyrjen e liruar ta vendosim në listën e hyrjeve të lira në
direktorium. Mënyra e tretë është që hyrjen e fundit në direktorium ta kopjojmë në vendin e lirë e
madhësinë e direktoriumit ta zvoglojmë për një.
Zgjedhje më e mirë se direktoriumi i organizuar si listë lineare është direktoriumi i
organizuar si listë e renditur. Direktoriumi i tillë i renditur mundëson kërkimin binar që dukshëm
zvoglon kohën e kërkimit. Algoritmi i tillë është më kompleks dhe kërkon që direktoriumi të
mbahet gjithnjë i renditur. Kjo fut disa probleme lidhur me krijimin dhe fshirjen e datotekave,
sepse mund të shkaktojë që sasi të konsiderueshme të të dhënave të kenë nevojë të çvendosen
nga një vend në tjetrin, në mënyrë që të ruhet renditja e direktoriumit. Që ky disadvantazh të
zbutet përdoret lista binare e lidhur.
Një strukturë tjetër e të dhënave që mund të shfrytëzohet për direktorium është hash
tabela. Hash tabela mund të zvoglojë kohën e kërkimit. Insertimi dhe fshirja janë poashtu të thje
shta. Problem me hash tabelë është madhësia e saj e kufizuar dhe varëshmëria e hash funksionit
nga madhësia e tabelës.
Shumica e operacioneve me datotekave është leximi dhe shkruarja në to. Gjatë leximit
pasi të kexohet një pjesë e datotekës treguesi i pozitës zhvendoset në pozitën e re aktuale për të
mundësuar leximin e bllokut të ardhshëm. Gjatë shkruarjes pasi të jetë regjistruar në fund të
32
datotekës e dhëna e re, treguesi zhvendoset në fund për të treguar pozitën ku do të shtohen të
dhënat e reja. Në disa sisteme është e mundur që programi t'i kërcejë n rekorde fizike përpara ose
prapa (në shumicën e rasteve n=1). Kjo mënyrë e qasjes quhet qasje sekuenciale. Mënyra
sekuenciale e qasjes është e bazuar në modelin e datotekës në shirit magnetik.
Qasja direkte mundëson që arbitrarisht të lexohet ose të shkruhet në cilindo bllok. Mund
të lexojmë bllokun 5, pas tij 19, në vazhdim të shruajmë diçka në bllokun 8 e kështu me rradhë.
Nuk ka kurrfarë kufizimesh në renditje të blloqeve që lexohen ose shkruhen ose në llojin e
operacionit që do të kryhet.
Qasja direkte përdoret kur na duhet qasje e shpejtë sasisë së madhe të informatave. Me të
ardhur të informatës se çka kërkohet, llogaritet cili bllok e përmban informatën e kërkuar dhe
përmbajtja e bllokut sjellet direkt në memorie operative.
Për tu realizuar kjo qasje operacionet e leximit dhe shkruarjes duhet të përmbajnë edhe
numrin e bllokut si parametër. Zakonisht do të kemi urdhëra të llojit read n (lexo n) ose write n
(shkruaj n). Mënyrë alternative është që të ruhet read next (lexo të ardhshmen) dhe write next
(shkruaj të ardhshmën) si te qasja sekuenciale, por me kusht që të shtohen urdhëri position file to
n (pozicionohu në n) ku n është numri i bllokut.
Numri i bllokut që e jep shfrytëzuesi është numër relativ dhe tregon pozitën e bllokut ndaj
pozitës fillestare të datotekës. Adresat absolute të blloqeve të datotekës në disk mund të
ndryshojnë, kështu që do të kemi p.sh. rastin kur blloku 0 i datotekës të jetë i vendosur në pozitën
33
12045 e blloku 1 në adresën 12046 (në shumë sistemi blloku i parë emrohet si bllok 0). Numrat
relativ të blloqeve i lejojnë sistemit operativ që të vendosë ku do ti vendosë datotekat dhe ia
pamundson shfrytëzuesit që me qëllim ose pa qëllim të shfrytëzojë hapësirën e datotekës tjetër
duke dëmtuar pa kthim të dhënat e saj.
Qasja sekuencile datotekës mund të simulohet me anë të qasjes direkte ashtu që do të
kemi një numrues që do të tregojë pozitën momentale, vlera e të cilit do të inkrementohet pas çdo
operacioni të leximit, respektivisht shkruarjes.
Metodat tjera të qasjes bazohen në mënyrën direkte të qasjes. Këto metoda nënkuptojnë
krijimin e indeksit të datotekës. Indeksi, ngjashëm me indeksin në fund të librit, tregon në blloqet
e ndryshme të datotekës. Kur të kërkojmë ndonjë të dhënë së pari e shikojmë indeksin e pasi ta
kemi gjetë informatën e kërkuar e shfrytëzojmë treguesin që direkt dhe menjëherë ti qasemi
bllokut të datotekës dhe në të ta gjejmë informatën e kërkuar.
Të marrim për shembull se për artikujt e shenuar me shifër 10 shifrore i kemi rezervuar 6
shifra për çmim. Për çdo artikull shfrytëzojmë 16 bajtë. Nëse blloqet tona janë 1024 bajtëshe
atëherë në një bllok mund të vendosim 64 artikuj të definuar kështu. Datoteka që do të përmbajë
120,000 artikuj do të ketë 1875 blloqe që do të zënë 1,920,000 bajtë. Duke e mbajtur datotekën
të renditur sipas shifrës së prodhimit mund të definojmë indeksin që do të përmbajë shifrën e
artikullit të parë në secilin bllok. Ky indeks do ti ketë 1875 elemente të gjatësisë 10 bajtë që
34
gjithsejt bënë 18750 bajtë, e që mund të ruhet në memorien operative. Që të gjejmë çmimin e
ndonjë artikulli të posaçëm së pari do ta kërkojmë (kërkimi binar) indeksin. Nga ky kërkim do të
gjejmë se cili bllok përmban artikullin e kërkuar, e pastaj do ti qasemi atij blloku. Përparësi tjetër e
kësaj mënyre qasjes së të dhënave në datotekë është numri i vogël i operacioneve hyrëse-dalëse të
nevojshme.
Kur datotekat janë të mëdha edhe indekset janë të mëdhenj për tu ruajtur në memorien
operative. Kjo mund të zgjidhet duke krijuar indeksin për indeks datotekën. Indeks datoteka
primare do të përmbajë treguesit në indeks datotekat sekondare, të cilat tregojnë në elemente
individuale.
Indeksi i vogël kryesor tregon në blloqet e diskut të indeksit sekondar. Blloqet e indeksit
sekondar tregojnë në blloqet e datotekave. Datoteka mbahet e renditur në bazë të çelësit të
definuar. Për të gjetë informatën e kërkuar, së pari bëhet kërkimi binar i indeksit kryesor, nga i cili
gjejmë numrin e bllokut të indeksit sekondar. Ky bllok sjellet në memorie dhe në kuadër të tij me
kërkim binar kërkojmë bllokun që përmban rekordin e dëshiruar. Më në fund ky bllok do të
kërkohet sekuencialisht. Në këtë mënyrë, cilido rekord mund të gjindet me anë të çelësit të vet
me më së shumti dy qasje direkte për lexim. Kjo mënyrë e qasjes është e zbatuar në makinat IBM
si ISAM (Indexed Sequential Accesss Method, shq. Metoda e qasjes sekuenciale të indeksuar).
Gjatë punës së kompjuterit datotekat shpesh krijohen dhe fshihen. Pasi hapësira në disk
është e kufizuar duhet gjetë mënyrë që hapësira e liruar nga datotekat e fshira të shfrytëzohet për
vendosjen e datotekave të reja. Që ta realizojë këtë sistemi i datotekave duhet të ketë dhe të
mirëmbajë listën e hapësirës së lirë. Për të krijuar datotekën e re sistemi do të shikojë në listën e
hapësirës së lirë për të gjetë sasinë e kërkuar nga datoteka. Nëse në sistem kemi aq hapësirë të lirë
sa kërkohet ajo do ti jepet datotekës. Më pastaj, kjo hapësirë do të fshihet nga lista e hapësirës së
lirë.
Zakonisht lista e hapësirës së lirë nuk është e organizuar si listë edhepse e ka emrin e tillë.
Zakonisht kjo listë implementohet si bit map ose bit vektor. Çdo bllok i diskut paraqitet në këtë
map si një bit. Nëse blloku është i lirë biti është 0, nëse blloku është i zënë biti është 1. Në bit
mapën e dhënë më poshtë do të kemi informatën se blloqet 0, 1, 4, 9 janë të zënë e të tjerët të lirë:
1100100001.....
Zgjidhje alternative do të ishte që të lidhim të gjitha blloqet e lira, duke ruajtur treguesin
në bllokun e parë të lirë. Ky bllok do të përmbajë treguesin në bllokun e ardhshëm të lirë. Në
35
shembullin tonë do të kishim treguesin i cili do të tregojë në bllokun 2 si bllok të parë të lirë,
blloku 2 do të tregojë në bllokun 3, e treguesi i bllokut 3 do të tregojë në bllokun 5 pasi blloku 4
është i zënë, treguesi i bllokut 5 do të tregojë në bllokun 6 e kështu me rradhë.
36
Adresat në disk definojnë renditjen lineare në disk.
Vendosja e pandërprerë e datotekës është e definuar me adresën fillestare të bllokut të
parë dhe gjatësia e datotekës. Nëse datoteka është e gjatë n blloqe ajo do të zë blloqet b, b+1, ...,
b+n-1. Hyrja në direktorium përmban për çdo datotekë adresën e bllokut fillestarë dhe gjatësinë e
datotekës.
Qasja datotekës së tillë është relativisht e thjeshtë. Kur qasja është sekuenciale, sistemi i
datotekave e mbanë në mend adresën e bllokut të fundit dhe atëherë kur është e nevojshme e
lexon bllokun e ardhshëm. Bllokut i të datotekës e cila fillon nga blloku b, e të cilës i qasemi në
mënyrë direkte, do t'i qasemi ashtu që do ti qasemi menjëherë bllokut b+i.
Problemi me këtë lloj të vendosjes së datotekave është në gjetjen e n blloqeve të
njëpasnjëshme të lira. Nëse përdorim bit mapën duhet gjetur n 0 të njëpasnjëshme, nëse përdorim
listën e adresave dhe numrave duhet gjetur adresën që është e shoqëruar me numër që është i
barabartë ose më i madh se n.
Hapësira në disk mund të trajtohet si fushë e blloqeve të diskut. Disa prej këtyre blloqeve
janë të lirë e disa të zënë. Më tutje hapësira në disk mund të trajtohet si koleksion i segmenteve të
37
lira dhe të zëna. Secili segment i tillë përbëhet nga disa blloqe të njëpasnjëshme. Segmenti i cili
nuk shfrytëzohet nga ndonjë datotekë quhet vrimë. Problemi i shpërnadarjes dinamike të
hapësirës memorike është problemi i kënaqjes së kërkesës për n blloqe nga lista e vrimave të lira.
Ka disa zgjidhje të këtij problemi. Do të përmendim tri:
E para që përgjigjet (First-fit). Datotekës i jepet vrima e parë e cila gjendet e që është
mjaft e madhe. Kërkimi mund të fillojë nga vrima e parë e lirë ose nga vrima e parë e lirë nga
kërkimi paraprak. Kërkimi ndërprehet sa të gjindet vrima e parë që kënaq kushtin të jetë e
barabartë ose më e madhe se n blloqe.
Më së miri që përgjigjet (Best-fit). Datotekës i jepet vrima më e vogël që kënaq
kushtin. Për ta gjetë këtë vrimë duhet kërkuar e tërë lista, duke përjashtuar rastin kur kjo listë
është e renditur sipas madhësisë së vrimës. Kjo strategji jep vrimë më të vogël si tepricë.
Më së keqi që përgjigjet (Worst-fit). Datotekës i jepet vrima më e madhe. Edhe në këtë
rast duhet kërkuar e tërë lista, përveç në rastin kur është e renditur sipas madhësisë së vrimës. Kjo
mënyrë e shpërndarjes dinamike len si tepricë vrimën më të madhe, që në anën tjetër mund të jetë
më e shfrytëzueshme se vrima tepricë më e vogël nga mënyra paraprake.
Provat kanë treguar se dy metodat e para janë më të mira se metoda e tretë si në
pikëpamje të shpejtësisë ashtu edhe të shfrytëzimit të hapësirës. Në pikëpamje të shfrytëzimit të
hapësirës asnjëra nga dy metodat e para nuk ka përparësi të posaçme. Metoda e parë është në
rastin e përgjithshëm më e shpejtë.
Të tri mënyrat e përmendura shkaktojnë copëzimin e jashtëm (fragmentimin ekstern) të
hapësirës memorike. Fragmentimi ekstern paraqitet kur ekziston hapësirë e mjaftueshme e lirë në
disk për të kënaq kërkesën, por kjo hapësirë nuk është e pandërprerë. Me këtë rast hapësira
memorike në disk është copëtuar në shumë vrima të vogla.
Kompaktëzimi
Që hapësira e lirë e ndarë në shumë vrima të vogla të bëhet përsëri e pandërprerë bëhet
kompaktëzimi. Gjatë kompaktëzimit bëhet kopjimi i përkohëshëm i datotekave në ndonjë njësi
tjetër (disk tjetër, shirit magnetik ose memorie operative) e pastaj rishkruarja e tyre në hapësirën
ku ndodheshin më parë. Gjatë kthimit në diskun amë datotekat kopjohen njëra pas tjetrës duke
shkaktuar që hapësira e lirë të jetë e koncentruar në një vrimë në fund të diskut. Kompaktëzimi
shpenzon kohë, por zgjedhë problemin e fragmentimit të hapësirës së lirë. Është e këshillueshme
që kompaktëzimi të bëhet pas fshirjes së më shumë datotekave ose herë pas herë (një herë në
javë).
38
që shoqërohet me lirimin e hapësirës së zënë paraprakisht. Ky aksion mund të përsëritet derisa në
sistem të ketë vrima të lira. Mirëpo në këtë rast shfrytëzuesi nuk ka nevojë të informaohet se çka
po ndodh në sistem me datotekën e tij. Kuptohet, kopjimi i datotekës dhe lirimi i hapësirës së lirë
ngadalson rrjedhën e programit.
Problem i veçantë janë datotekat të cilat rriten ngadalë gjatë një kohe shumë të gjatë (javë
ose muaj, ndonjëherë vite). Në këtë rast nak ka kuptim që datotekës t'ia rezervojmë tërë
hapësirën edhe nëse e dijmë se sa do të jetë e madhe datoteka përfundimisht. Kjo do të ishte
thjeshtë joekonomike.
39
Fig.3.8 Vendosja e lidhur
Dobësi tjetër e kësaj mënyre të vendosjes është shpenzimi i hapësirës për ruajtjen e
treguesve.
Ndoshta, problemi potencialisht më i rrezikshëm është siguria e të dhënave. Nëse në
ndonjërin prej blloqeve vlera e treguesit humbet ose ndërrohet datoteka do të jetë praktikisht e
pashfrytëzueshme. Gabimi në program ose hardver mund të krijojë blloqe të lidhura pa kurrfarë
kuptimi. Një mënyrë për zbutjen e këtij problemi është shfrytëzimi i listave dyfish të lidhura, ku
treguesit nuk tregojnë vetëm bllokun e ardhsëm por edhe atë paraprak, ose duke ruajtur emrin e
datotekës dhe numrin relativ të bllokut në çdo bllok. Këto përmirësime rrisin hapësirën e shfrytë
zuar në mënyrë joefektive.
40
Fig.3.9 Vendosja e indeksuar
41
shfrytëzimin e ndonjë treguesi të veçantë). Që të mundësohet krijimi i datotekave më të mëdha
mund të lidhen së bashku më shumë indeks datoteka. Mund të kemi rastin kur indeks blloku
përmban infomatën për emrin e datotekës dhe 100 tregues (adresa) të blloqeve. Nëse datoteka
është e vogël treguesi i fundit nga tabela do të ketë vlerën zero për të treguar se nuk ka më
blloqe. Nëse datoteka ka më shumë se 100 blloqe atëherë treguesi i fundit do të tregojë në indeks
datotekën e ardhshme. Nëse datoteka është shumë e madhe indeks blloku i dytë mund të tregojë
në indeks bllokun e tretë e kështu me rradhë.
Nëse e shikojmë më me kujdes këtë organizim të indeks blloqeve do të shohim se për
vendosjen e indeks blloqeve është përdorë vendosja e lidhur. Një variantë e kësaj mënyre është
përdorimi i indeks bllokut, elementet e të cilit do të tregojnë në indeks blloqet, të cilët pastaj do të
tregojnë në blloqet e datotekës. Që ti qaset një blloku të datotekës sistemi operativ shfrytëzon
indeksin e nivelit të parë për të gjetë indeksin e nivelit të dytë, përmes të cilit pastaj, do ta gjejë
bllokun e dëshiruar. Ky nivelizim i indeks blloqeve mund të vazhdojë në tri ose katër nivele, por
zakonisht dy nivele mjaftojnë. Me 256 tregues në një bllok, me dy nivele të indekseve do të mund
t'i qasemi 65536 blloqeve. Nëse blloku është 1024 bajtësh atëherë do të mund të kemi datotekë
prej 67,108,864 bajtë, që shumë rralë mund të haset. Sistemi operativ UNIX përdorë skemën e
vendosjes së indeksuar ku në direktoriumin e njësisë për çdo datotekë ruhen të themi 15 tregues.
Nëse datoteka është më e vogël kjo është krej çka na nevojitet. Nëse datoteka është më e madhe
atëherë treguesi i fundit, i 16-ti, tregon në listën e indeks blloqeve. Në këtë mënyrë për datoteka
të vogla nuk shfrytëojmë indeks bllokun.
42
kërkojmë datotekat që në emër kanë një mostër të caktuar, p.sh. të gjejmë të gjitha datotekat emri
i të cilave fillon ta zëmë me pro.
Krijimi i datotekave. Duhet të kemi mundësi për krijimin e datotekave të reja dhe
vendosjen e tyre në direktorium.
Fshirja e datotekave. Datotekën që nuk na nevojitet do ta fshijmë e të dhënat për te ti
largojmë nga direktoriumi.
Shfletimi i direktoriumit. Duhet të kemi mundësi ta shfletojmë tërë direktoriumin dhe të
gjitha të dhënat për çdo datotekë nga direktoriumi.
Backupi. Për arsye të sigurisë së të dhënave në rast të prishjes së kompjuterit, është e
nevojshme që herë pas herë të kopjohen të gjitha të dhënat (zakonisht nga disku) në ndonjë njësi
tjetër (shirit magnetik). Me këtë rast kopjohen datotekat dhe e tërë struktura e direktoriumeve
dhe të dhënave tjera të rëndësishme. Poashtu, me këtë mund të lirojmë hapësirën në disk, duke i
bartur në shirit datotekat të cilat nuk do ti përdorim për një kohë të caktuar e hapësirën në disk
t'ua lëmë datotekave të reja.
Kjo strukturë e direktoriumit ka kufizime të cilat vijnë në shprehje kur numri i datotekave
rritet ose kur kemi më shumë se një shfrytëzues. Datotekat në një direktorium duhet të kenë emra
të ndryshëm. Sikur dy shfrytëzues ta përdorin të njejtin emër atëherë mund të ndodhë që
përmbajtja e datotekës së parë të humbet. Po edhe një shfrytëzues mund të ketë problem me
emrimin e datotekave. Në të shumtën e rasteve datotekave u jepet emri që në njëfarë mënyrë
pasqyron përmbajtjen e tyre. Numri i shkronjave ose simboleve tjera për ta emruar datotekën
është zakonisht i kufizuar në 6, 8, 14 simbole. Për këtë arsye paraqiten edhe dilema gjatë emrimit
të datotekave që kanë përmbajtje të ngjashme.
43
3.5.2 Direktoriumet dynivelëshe
Kur shfyrëtuesi e kërkon ndonjë datotekë sipas emrit, vetëm direktoriumi i tij do të
kërkohet. Në këtë mënyrë shfrytëzues të ndryshëm mund ti emrojnë datotekat e veta me emër të
njejtë.
Krijimi i datotekës se re ose fshirja e datotekës ka të bëjë vetëm me kërkimin e datotekës
me të njejtin emër në kuadër të atij direktoriumi. Nëse datoteka me emër të tillë ekziston nuk
mund të krijohet tjetra me po at emër. Rreziku që një shfry-tëzues ti fshijë datotekat e një tjetrit
është eliminuar.
Sistemi duhet të ketë mundësi të shtimit ose fshirjes së direktoriumeve të shfrytëzuesit.
Program i posaçëm sistemor e krijon direktoriumin e ri dhe ia shton direktoriumit kryesor.
Përdorimi i këtij programi është zakonisht i kufizuar. Ndarja e hapësirës për direktoriumin e
shfrytëzuesit mund të bëhet me metoda të njejta të përdorura për vendosjen e datotekave.
Ndarja e plotë e shfrytëzuesve është e mirë nëse puna e tyre s'ka nevojë për kurrfarë
bashkëpunimi, por paraqet problem kur shfrytëzuesit dëshirojnë të bashkëpunojnë mes veti.
Nëse do të lejojmë qasjen direktoriumit tjetër, atëherë njëri shfrytëzues duhet të jetë në
gjendje të emrojë datotekat e tjetrit. Emri duhet të përfshijë në vete edhe emrin e shfrytëzuesit,
përveç emrit të datotekës. Kështu do të sigurohemi se në direktoriumin dynivelësh datotekat kanë
emra unik.
Direktoriumi dynivelësh mund të trajtohet si pemë me lartë-si 2. Rrënja e pemës është
direktoriumi kryesor (quhet edhe direktoriumi rrënjë). Pasardhësit direkt të tij janë direktoriumet
e shfrytëzuesve. Pasardhës të direktoriumeve të shfrytëzuesve janë vetë datotekat. Datotekat
44
mund ti konsiderojmë si gjethe të pemës. Përcaktimi i emrit të shfrytëzuesit dhe emrit të
datotekës definon shtegun në pemë që shkon nga rrënja (dire-ktoriumi kryesor) deri të gjethi
(datoteka). Emri i shfrytëzuesit dhe emri i datotekës definojnë së bashku emrin e shtegut. Çdo
datotekë në sistem e ka emrin unik të shtegut. Për të emruar njëvlershëm cilëndo datotekë në disk
shfrytëzuesi duhet të dijë emrin e shtegut të datotekës së kërkuar. Sintaksa e emrit të një shtegu
të tillë mund të jetë e formës (për datotekën TEST):
/SHFRA/TEST ose TEST[SHFRA] ose \SHFRA\TEST ose ndryshe,
që të gjitha tregojnë në datotekën TEST të shfrytëzuesit A (emri simbolik SHFRA)
Në kompjuter zakonisht ekzistojnë datoteka (programe) sis-temore, siç janë për shembull
kompajlerët për gjuhë të ndryshme programore, loaderët, programet ndihmëse, libraritë etj.
Shumë komandë interpreterë i trajtojnë emrat e datotekave si emra të programeve të cilat duhen
lexuar në memorie dhe ekzekutuar. Nëse jemi në njërin nga direktoriumet e shfrytëzuesit, sistemi
ope-rativ do të kërkojë programin e tilë për ta gjetë dhe ekzekutuar. Zakonisht, kërkimi nuk do të
ketë sukses sepse këto datoteka rralë ndodhen në ndonjërin nga direktoriumet e shfrytëzuesve.
Problemi mund të zgjidhet nëse këto datoteka sistemore i ko-pjojmë në direktoriumet e
shfrytëzuesve. Mirëpo kjo zgjidhje është jopraktike dhe shpenzon sasi të konsiderueshme të
hapësirës memorike. Zgjidhje më elegante është që këto datoteka të vendosen në direktorium të
posaçëm (me emër p.sh. SHFR0). Sa herë që shfrytëzuesi dëshiron të ekzekutojë ndonjë
program, ai program së pari do të kërkohet në direktoriumin e tij dhe do të startohet nëse është
aty. Nëse nuk ndodhet në direktoriumin e shfrytëzuesit, programi i përmendur do të kërkohet
automatikisht në direktoriumin e veçante (në rastin tonë në direktoriumin SHFR0) dhe nëse
gjindet aty do të ekzekutohet. Sekuenca e dire-ktoriumeve që do të kërkohet sa herë që
dëshirojmë ti qasemi ndonjë datoteke quhet shtegu i kërkimit (ang. search path).
45
Krijimi i nëndirektoriumeve i mundëson shfrytëzuesve që datotekat ti vendosin në
nëndirektoriume sipas dëshirës së vet, zakonisht sipas përmbajtjes që kanë.
Fshirja e direktoriumit mund të bëhet në dy mënyra. Zako-nisht së pari duhet të fshihen të
gjitha datotekat dhe eventualisht nëndirektoriumet dhe datotekat e tyre, e pastaj të fshihet edhe ai
vetë. Mënyra e dytë nënkupton se me fshirjen e direktoriumit fshihen automatikisht edhe të gjitha
datotekat dhe nëndi-rektoriumet si dhe datotekat në to, sado thellë që të jenë.
Datotekave të shfrytëzuesve tjerë mund ti referohemi nëse e dijmë emrin e shtegut deri te
ajo datotekë. Poashtu edhe shtigjet e kërkimit të datotekave, mund të shkruhen ashtu që, pasi të
jetë kërkuar datoteka në direktoriumin punues dhe në direktoriumin e datotekave sistemore të
kërkohet edhe direktoriumi punues i ndonjë shfrytëzuesi tjetër.
46
projekti janë të vendosura në një nëndirektorium. Mirëpo pasi të dy programerët janë të
interesuar që gjithmonë të kenë mundësi ti qasen pa probleme datotekave të tilla, dëshirojnë që ky
nëndirektorium të jetë në direktoriumin e tyre në kuadër të direktoriumit kryesor (MFD). Që kjo
të bëhet, nëndirektoriumi i tillë duhet të deklarohet si i përbashkët (ang. shared, prej share shq.
me nda mes veti, me shfrytëzu së bashku). Këtu nuk kemi të bëjmë me dy kopje. Kur kemi dy
kopje të datotekës ose direktoriumit ndryshimet që i bënë një shfrytëzues nuk përcjellen në
kopjen e shfrytëzuesit tjetër. Kur është fjala për datoteka ose direktoriume të përbashkëta ndry-
shimi që bën njëri shfrytëzues menjëherë vërehet edhe nga shfry-tëzuesi tjetër për arsye se fjala
është për një datotekë ose direktorium të vetëm.
47
kësaj lidhëse tregon emrin e vërtetë të datotekës ose direktoriumit. Tani me ndihmën e lidhë-ses
(emrit komplet të shtegut) dhe emrit të vërtetë të datotekës e gjejmë ku ndodhet datoteka e
kërkuar. Lidhëset identifikohen lehtë përmes formatit të veçantë. Quhet edhe tregues indirekt.
Qasje tjetër në implementimin e datotekave të përbashkëta është thjeshtë kopjimi i të
dhënave për datotekën e përbashkët në të dy direktoriumet që e shfrytëzojnë. Problemi i kësaj
qas-jeje është mbajtja e konzistencës së të dhënave në rast të modi-fikimit të datotekës. Është e
nevojshme që të gjitha ndërrimet të përcjellen në të dy direktoriumet, që ndonjëherë nuk është
edhe aq thjeshtë.
Struktura aciklike e direktoriumit është më fleksibile por edhe më komplekse. I pari send
që vërejmë është se tani e njejta datotekë mund të ketë më shumë shtigje komplete të ndryshme.
Rrjedhimisht emra të ndryshëm të datotekave munden në fakt ti referohen të njejtës datotekë.
Problem kemi nëse dëshirojmë të kontrollojmë tërë sistemin e datotekave për të kontrolluar
madhësinë e tyre ose për ti kopjuar ose për të kryer çfarëdo operacioni tjetër. Në shumë raste të
tilla nuk kemi dëshirë që të dhënave të përbashkëta ti qasemi më shumë se njëherë.
Problem tjetër i rëndësishëm është fshirja e datotekave. Në çfarë kushtesh duhet të lirohet
hapësira e zënë nga datoteka e përbashkët. Një mundësi është që kjo hapësirë të lirohet në
momentin kur cilido nga shfrytëzuesit ta fshijë datotekën. Ky operacion mund të lë në
direktoriumet e shfrytëzuesve tjerë tregues në datotekën joekzistuese. Rast më i keq do të ishte
sikur kjo hapësirë e liruar në këtë mënyrë të rishfrytëzohet nga ndonjë datotekë tjetër. Në atë rast
treguesit e mbetur mund të tregojnë edhe në mes të ndonjë datoteke tjetër.
Në sistemet e direktoriumeve ku datotekat e përbashkëta janë realizuar përmes lidhëseve
ku problem më lehtë zgjidhet. Fshirja e lidhëses nuk do ta prek datotekën - në këtë rast vetëm
lidhja është eliminuar. Nëse hyrja në direktorium për vetë datotekën është fshirë hapësira
memorike do të lirohet, duke lënë treguesit të tregojnë në datotekën joekzistuese. Mund të
kërkojmë direktoriumet për këto lidhëse dhe ti fshijmë edhe ato, por kjo mund të jetë joracionale,
përveç në rastin kur për çdo datotekë ekziston lista e lidhëseve shoqëruese. Në rastin tjetër,
lidhëset mund të lihen deri në momentin kur të tentojmë ti përdorim. Ky rast do të trajtohet si
rasti i datotekës joekzistuese për arsye se në atë rast datoteka emri i së cilës është dhënë nga
lidhësja nuk ekziston e ne nuk do të kemi mundësi të krijojmë emrin e lidhëses. Qasja e tentuar do
të trajtohet si cilado qasje datotekës me emër jovalid.
Qasje tjetër fshirjes së datotekave është që datoteka të ruhet derisa të fshihen të gjitha
referencat e bëra asaj. Që kjo të realizohet duhet gjetur ndonjë mekanizëm që do të na tregojë se
referenca e fundit e bërë datotekës është fshirë. Kjo mund të realizohet me ruajtjen e listës së
referencave që i janë bërë datotekës. Në momentin kur të krijohet lidhësja ose kur një hyrje në
listën e direktoriumeve të kopjohet edhe në një direktorium tjetër, në këtë listë të referencave do
të shtohet një element. Fshirja e ndonjë lidhëseje ose fshirja e emrit të datotekës nga ndonjë
direktorium do të ketë si pasojë heqjen e elementit gjegjës nga lista e referencave. Në momentin
kur kjo listë të jetë e zbrazët datoteka do të fshihet e hapësira e okupuar nga ajo do të lirohet.
Problemi me madhësinë e listës së referencave të bëra datotekës ose direktoriumit mund
të zgjidhet nëse do të ruajmë vetëm numrin e referencave e jo edhe emrin e datotekës ose
direktoriumit të lidhur me të. Kur vlera e këtij numruesi të jetë zero datoteka mund të fshihet.
Problemi kryesor gjatë përdorimit të strukturës aciklike është sigurimi se në graf nuk
ekziston cikli i mbyllur. Te direktoriumi me strukturë të pemës shtimi i datotekave dhe
direktoriumeve të reja nuk do ta shkatërrojë natyrën ekzistuese të pemës. Mirëpo me lejimin e
shtimit të lidhëseve në strukturën ekzistuese të pemës shumë shpejt kjo strukturë do të
48
shkatrrohet duke u degjeneruar në strukturë me formë të grafit të thjesht.
Kur të dhënat mbahen në sistem kompjuterik, është e nevoj- shme që ato të mbrohen nga
dëmtimet fizike të sistemit dhe nga qasja e paautorizuar.
Mbrojtja nga dëmtimet fizike të sistemit mund të bëhet me krijimin e kopjeve të
datotekave. Te shumë sisteme operative ky kopjim bëhet automatikisht në intervale të caktuara
49
kohore. Kopja e tillë e përmbajtjes së tërësishme vendoset zakonisht në shirita magnetik. Sistemi i
datotekave mund të shkatrrohet për arsye të ndonjë defekti në hardver, në shumicën e rasteve
gjatë leximit ose shkruarjes, për shkak të ndryshimeve të tensionit furnizues ose ndërprerjeve të
rrymës, dëmtimit të kokave të diskut, papastërtia, temperatura e lartë ose thjeshtë vandalizmi i
shfrytëzuesit. Shkatërimin e sistemit të datotekave mund ta shkaktojë gabimi në softver ose
programi i shkruar me këtë qëllim (viruset).
Mbrojtja nga qasja e paautorizuar mund të bëhet me mënyra të ndryshme. Ndonjëherë
mjafton që disketa me programe të nxjerret nga njësia dhe të mbyllet në sirtar.
Te sistemet multi-shfrytëzuese (ang. multi-user) një nivel i mbrojtjes realizohet ashtu që
një shfrytëzuesi nuk i lejohet qasja të dhënave të shfrytëzuesit tjetër. Ky është niveli maksimal i
mbrojtjes. Qasja e kundërt është që të gjithë shfrytëzuesve ti lejohet qasja secilës informatë, pa
kurrfarë mbrojtjeje. Zakonisht, ajo çka shfrytëzuesit kërkojnë është e njohur si qasje e kontrolluar.
Mekanizmat mbrojtës ofrojnë qasje të kontrolluar duke kufizuar tipet e qasjes që mund të
bëhen. Qasja do të lejohet ose refuzohet varësisht nga shumë faktorë, njëri nga të cilit është lloji i
qasjes së kërkuar. Mund të kontrollohen disa lloje të operacioneve.
Leximi. Leximi nga datoteka.
Shkruarja. Shkruarja ose rishkruarja e datotekës.
Ekzekutimi. Leximi i datotekës në memorie dhe ekzekutimi i saj.
Shtimi. Shtimi i të dhënave të reja në fund të datotekës.
Fshirja. Fshirja e datotekës dhe lirimi i hapësirës.
Mund të kontrollohen edhe operacionet tjera siç janë riemërimi, kopjimi ose editimi. Këto
funksione të nivelit më të lartë zakonisht realizohen përmes thirrjeve sistemore të nivelit më të
ultë siç është leximi. Shfrytëzuesi që ka lejen për të lexuar datotekën do të mundet edhe ta
kopjojë pasi që kopjimi përcjellet me lexime sukcesive të blloqeve të datotekës.
Operacionet mbi direktoriume që duhet të kontrollohen janë zakonisht operacionet e
krijimit dhe fshirjes së hyrjes së datotekës në direktorium. Operacion i kontrolluar duhet të jetë
edhe listimi i direktoriumit për arsye se ndonjëherë edhe vetë informata për ekzistencën ose
mosekzistencën e ndonjë datoteke ose nëndirektoriumi do të jetë informatë që duhet të mbrohet
nga qasja e paautorizuar.
3.6.1 Emrimi
Mbrojtja përmes emrit nënkupton se shfrytëzuesi nuk mund ti qaset datotekës emrin e të
cilës nuk e di. Kjo ka të bëjë me sistemet ku emrat e datotekave nuk do të jenë në dispozicion
shfrytëzuesit përmes ndonjë programi tjetër. Por pasi emri i datotekës sipas rregullit ka njëfarë
kuptimi, e rrallë herë është i formës p.sh. a3"V--=?v, nuk është e përjashtuar që shfrytëzuesi i
durueshëm t'ia qëllojë.
3.6.2 Parullat
Mbrojtja e datotekave mund të bëhet ashtu që çdo datoteke ti bashkangjitet parulla (ang.
password), në mënyrë të njejtë sikurse qasja kompjuterit kërkon dhënjën e parullës së shfrytëzu
esit. Nëse këto parrula janë të zgjedhura ashtu që nuk paraqesin ndonjë kuptim dhe nëse
ndërrohen shpesh, mbrojtja mund të jetë efektive.
50
Qasja mund të bëhet e varur nga identiteti i shfrytëzuesit. Shfrytëzues të ndryshëm kanë
nevojë për qasje të ndryshme datotekave ose direktoriumeve. Për çdo datotekë mund të lidhet
lista e qasjes që përmban emrin e shfrytëzuesit dhe llojin e lejuar të qasjes. Kur shfyrëtzuesi të
kërkon qasje datotekës do të kontrollohet lista e qasjes dhe nëse për atë shfrytëzues nuk është i
lejuar tipi i kërkuar i qasjes, programi i tij do të ndërprehet.
Problemi me listat e qasjes është gjatësia e tyre. Për të shkurtuar listat e tilla sistemet
operative i klasifikojnë shfrytëzuesit në tri grupe, në raport me datotekën. Këto janë pronari,
grupi dhe gjithë të tjerët. Pronari i datotekës është ai shfrytëzues që e ka krijuar datotekën. Pasi
pronari i datotekës mund ti takojë grupit që është duke punuar në të njejtin projekt, është e
dëshirueshme që anëtarët e grupit të kenë mundësi qasjes datotekës në fjalë. Më në fund i kemi të
gjithë të tjerët.
Sipas këtij klasifikimi janë të nevojshme tri fusha për të realizuar konceptin e menduar të
mbrojtjes. Çdo fushë përbëhet nga koleksioni i bitave që kontrollojnë qasjen e cila është e lidhur
me atë bit. Në sistemin operativ UNIX ekzistojnë tri fusha secila me nga tre bita. Bitat janë r, w
dhe x dhe respektivisht kontrollojnë leximin, shkruarjen dhe ekzekutimin. Fushat i takojnë
pronarit, grupit dhe gjithë të tjerëve. Pra, për çdo datotekë përdoren nëntë bita, për të definuar të
drejtën e qasjes.
Mbrojtja mund të jetë e lidhur me vetë datotekën ose me shtegun e përdorur për të
specifikuar datotekën. Nëse mbrojtja është e lidhur me shtegun leja e qasjes duhet të jetë e dhënë
për qasje edhe shtegut edhe datotekës. Në sistemet e direktoriumeve me strukturë aciklike ose
me formë të përgjithshme të grafit, për një shfrytëzues të dhënë e drejta e qasjes një datotekës do
të varet edhe nga shtegu i specifikuar.
51
formatin e strukturës së direktoriumeve. Për tu krijuar datoteka e re, nga disku do të lexohet
direktoriumi dhe pasi në te të shtohet hyrja e re për datotekën e re, do të shkruhet përsëri në disk.
Direktoriumet do të trajtohen njësoj si datotekat. Në fushën për tipin e datotekës ato do të kenë
indikatorin që tregon se fjala është për direktorium. Kështu, Sistemi logjik i datotekave mund ta
thërret Modulin e organizimit të datotekave që ta mapojë operacionin e hyrje-daljes mbi
direktorium në numra të blloqeve që do ti përcjellen Sistemit themelor të datotekave dhe Sistemit
të kontrollit të hyrje-daljes.
Pasi që ta kemi azhuruar direktoriumin, Sistemi logjik i datotekave mund ta shfrytëzojë
atë (direktoriumin) që të kryej operacionet e hyrje-daljes. Kur të jetë hapur datoteka, struktura e
direktoriumeve do të kërkohet për tu gjetë hyrja e dëshiruar për këtë datotekë. Është e mundur
që për çdo operacion të hyrje daljes të kërkojmë direktoriumin, por kjo do të ishte e panevoj
shme. Për këtë arsye përdoret tabela e datotekave të hapura e cila përdoret për çdo referim të
mëtejshëm datotekës derisa ajo të jetë e hapur. Ky referim bëhet përmes indeksit (deskriptorit ose
përshkruesit) të datotekës, e jo më përmes emrit simbolik të saj. Çdo ndërrim për datotekën e
hapur bëhet në tabelën e datotekave të hapura. Pasi të mbyllet datoteka hyrja e azhuruar kopjohet
në direktorium.
52
qasjes në momentin e hapjes së datotekës. Thirrje të veçanta sistemore përdoren për operacionet
e hapjes për lexim dhe për hapjen për shkruarje. Duhet pasë kujdes që datoteka e hapur përmes
thirrjes sistemore të hapjes për lexim të mbrohet nga shkruarja eventuale.
53
4 Planifikimi i punës së njësisë qendrore
54
ekzekutohet 1 sekond e pastaj pret 1 sekond. E tërë kjo procedurë përsëritet 60 herë. Nëse së
pari do të startojmë punën A e me të kryer të saj punën B, e tërë koha e nevojshme për
ekzekutimin e këtyre dy punëve do të jetë 4 minuta, 2 për punën A dhe 2 për punën B. Gjatë
kësaj kohe procesori ka qenë i angazhuar gjithsej 2 minuta. Koha tjetër është humbur në pritje.
Shfrytëzimi i procesorit është 50%.
Nëse i multiprogramojmë punët A dhe B, do të përmirësojmë dukshëm performansat e
sistemit. Edhe tash do të startojmë punën A, por në momentin kur puna A duhet të presë 1
sekond procesorin do t'ia japim punës B e cila do të ekzekutohet një sekond deri sa të ndalet, për
të vazhduar pastaj përsëri me punën A e kështu me rradhë deri sa ekzekutimi i të dy punëve të
kryhet. Koha e shpenzuar për kryerjen e këtyre dy punëve është 2 minuta. Procesori gjatë kësaj
kohe është shfrytëzuar 100%, e numri i punëve të kryera në njësi të kohës është rritë. Duhet
vërejtur këtu se koha për të cilën është kryer puna A ka mbetë e njejtë, por është përgjysmuar
koha e nevojshme për kryerjen e punës B, prej 4 në 2 minuta.
Siç thamë në fillim kjo është vetëm një rast kufitar që rralë mund të ndodhë në praktikë,
por është ilustrativ për të treguar përparësitë e multiprogramimit.
Planifikimi kohorë është funksion fundamental i sistemit operativ. Për të gjitha resurset e
sistemit kompjuterik, para përdorimit të tyre ekziston njëfarë plani, orari i përdorimit të tyre.
Njësia qendrore ose procesori është pjesë e këtij sistemi. Planifikimi kohor i punës së njësisë
qendrore është koncept themelor i projektimit të sistemit operativ.
Njësia qendrore ekzekuton numër të madh të punëve. Por, përveç punëve dhe
programeve të shfrytëzuesve njësia qendrore merr pjesë edhe në kryerjen e aktiviteteve tjera të
sistemit kompjuterik. Çdo aktivitet i tillë inicohet nga procesori. Procesori duhet edhe të reagojë
në gabime, kërkesa të programeve dhe ndërprerje për shkak të hyrje-daljes.
Aktivitetet që kryen njësia qendrore mund të emërohen në mënyra të ndryshme. Në batch
sistem njësia qendrore do të ekzekutojë punët, e në sistemin interaktiv programet e shfrytëzuesit.
Edhe në sistemin me një shfrytëzues, do të kemi rastin kur në kompjuter do të ekzekutohen disa
programe njëkohësisht: një interaktiv e të tjerët si batch programe. Edhe në rastin kur shfrytëzuesi
mund të ekzekutojë vetëm një program në një interval kohor, është e mundur që sistemi operativ
duhet të përkrahë aktivitetet e parapara me program siç është p.sh. spoolingu.
Të gjitha këto aktivitete janë të ngjashme në shumë pikëpamje. Për këtë arsye të gjitha
55
këto i quajmë procese. Proces është programi që ekzekutohet. Batch programi është proces.
Programi i shfrytëzuesit është proces. Proces është edhe aktiviteti tipik i sistemit operativ,
spoolingu i përmendur. Në sisteme të ndryshme operative procesi quhet punë (ang. job),
shfrytëzues (ang. user), program, detyrë (ang. task) ose aktivitet. Do të konsiderojmë se proces
është një punë ose një program i shfrytëzuesit që punon si time sharing program, edhepse
koncepti është shumë më i përgjithshëm.
Në vazhdim shprehjet proces dhe punë do të kenë kuptim të njejtë si edhe shprehjet
procesorë dhe njësi qendrore të cilën lexuesi me siguri e ka vërejtur.
Proceset kanë një cilësi që është shfrytëzuar për të bërë planifikimin kohor të tyre.
Ekzekutimi i një procesi paraqet ndërrim alternativ të aktivitetit të procesorit dhe pritjes për
hyrje/dalje. Ekzekutimi i procesit fillon me një "breshëri" të procesorit (ang. CPU burst, rrjedhë
e instruksioneve të pandërprera të procesorit), për të vazhduar pastaj me një "breshëri" të
hyrje/daljes (ang. Input/Output burst), e kështu alternativisht deri sa të kryhet ekzekutimi i
procesit, që zakonisht bëhet në momentin kur njësia qendrore të ekzekutojë kërkesën për
përfundim të ekzekutimit. Gjatësia e këtyre breshërive të
instruksioneve të procesorit është matë dhe megjithëse mund të ndryshojë prej një procesi në
tjetrin ose prej një kompjuteri në tjetrin ka formën që është e ngjashme me atë në figurën e dhënë.
Nga ky diagram shihet se kemi një numër të madh të breshërive të shkurta të instruksioneve dhe
një numër më të vogël të breshërive më të gjata. Programi i orientuar më shumë në operacione
hyrëse-dalëse do të ketë më shumë kësi breshërish të shkurta të procesorit. Programi i orientuar
më shumë në aktivitete të procesorit, do të ketë disa breshëri që zgjasin më shumë. Të dhënat e
marra nga këto histograme janë të nevojshme për caktimin e algoritmit të planifikimit kohor.
Gjendjet e procesit
56
mbarojnë me breshëri të procesorit. Çdo proces mund të jetë në njërën nga këto gjendjet: i ri,
aktiv, duke pritur dhe i ndalur.
Një klasifikim i tillë i gjendjeve mund të zgjërohet edhe më tutje. Procesi i cili është duke
pritur që të ekzekutohet nga procesori do të trajtohet si i gatshëm. Procesi i cili është duke u
ekzekutuar do të jetë në gjendjen ekzekutohet.
Secili proces i paraqitet sistemit operativ përmes bllokut kontrollues të procesit. Blloku
kontrollues i procesit është bllok i të dhënave që përmbanë informata për procesin specifik duke
përfshirë këtu:
Gjendjen e procesit që mund të jetë i ri, i gatshëm, ekzekutohet, pret ose i ndalur.
Numruesin programor që tregon adresën e instruksionit të ardhshëm që do të
ekzekutohet për këtë proces.
Regjistrat e procesorit, numri i të cilëve mund të ndryshojë si në numër ashtu edhe në
tip, varësisht nga arkitektura e kompjuterit. Këtu hyjnë përmbajtjet e akumulatorit, regjistrave me
destinim të përgjithshëm, indeks regjistrit dhe status regjistrit. Këto të dhëna shërbejnë për
vazhdimin e rregullt të procesit.
Informatat për gjendjen e memories, duke përfshirë këtu regjistrat e bazës dhe të
brezit ose tabelat e faqeve.
Informatat statistikore duke përfshirë këtu kohën e shfry-tëzuar të procesorit, limitet
kohore, numrin e proceseve etj.
Informatat për statusin e operacioneve të hyrje-daljes që përfshijnë kërkesat aktuale
57
për hyrje-dalje, numrin dhe llojin e njësive hyrëse-dalës të ndara procesit, listën e datotekave të
hapura e të ngjashme.
Informatat për planifikimin kohor të procesorit siç janë prioriteti i procesit, treguesit
në rreshtat e pritjes dhe çfarëdo informate tjetër për këtë qëllim.
Pra, siç shihet blloku kontrollues i procesit shërben për ruajtjen e të gjitha informatave
relevante për proces, të cilat, kuptohet, janë të ndryshme për secilin proces.
Blloqet kontrolluese duhet të ruhen në memorien e rezervuar për monitor. Mënyra më e
lehtë është që paraprakisht të deklarohet numri maksimal i proceseve dhe për ta të rezervohet
hapësira e nevojshme. Pasi numri i proceseve do të ndryshojë me kohën, është e mundur që
sistemi operativ të përdorë mënyrën dinamike
58
Fig.4.8 Kalimi i procesorit nga njëri në tjetrin shfrytëzues
të dhënjës së memories për vendosjen e këtyre blloqeve. Mënyra dinamike e vendosjes së bloqeve
kontrolluese të proceseve ofron më shumë fleksibilitet, shpenzon më pak memorien, por në anën
tjetër është më komplekse për realizim dhe më e ndieshme në gabime eventuale.
4.2.2 Rreshtat
59
njësie tjetër. Mirëpo, njësia e kërkuar mund të jetë në atë moment e zënë nga ana e ndonjë procesi
tjetër. Lista e proceseve që presin në ndonjë njësi të caktuar quhet rresht i njësisë. Çdo njësi e ka
rreshtin e vet të njësisë. Nëse fjala është për njësi që i dedikohet procesit (që nuk mund të
shërbejë më shumë se një proces) siç është për shembull time-sharing terminali, rreshti i njësisë
nuk do të ketë asnjëherë më shumë se një proces. Por, nëse njësia mund të shfrytëzohet nga më
shumë procese atëherë në rreshtin e njësisë do të ketë më shumë se një proces.
Për të treguar këtë diskutim skematikisht, përdoren diagramet, elementet e të cilëve janë
një rresht i proceseve të gatshme dhe disa rreshta të njësive. Me rrathë janë të treguar resurset e
sistemit ndërsa me shigjeta është treguar rrjedha e proceseve në sistem.
Procesi hyn në sistem duke u vendosur në rreshtin e proceseve të gatshme. Në këtë rresht
ai pret deri në momentin kur ti vjen rradha të ekzekutohet. Kur procesi ka nevojë për kryerjen e
hyrje-daljes nga njësia e caktuar, ai vendoset në rreshtin e njësisë gjegjëse. Me të kryer të hyrje-
daljes, procesi prap vendoset në rjeshtin e proceseve të gatshme. Kjo vazhdon deri sa ekzekutimi
i procesit të kryhet; pas kësaj procesi del nga sistemi.
60
Fig.4.10 Prezentimi i planifikimit të procesorit përmes diagrameve të rreshtave
4.2.3 Planifikuesit
Planifikuesi afatgjatë ose planifikuesi i punëve (ang. job scheduler) përcatkon se cila punë
do të pranohet në sistem për tu procesuar. Në batch sistem zakonisht ekzistojnë më shumë punë
se sa mund të ekzekutohen menjëherë. Këto punë vendosen në disk, ku do të ruhen për tu
61
ekzekutuar më vonë. Planifikuesi afatgjatë i zgjedh punët nga ky grup i punëve dhe i vendosë në
memorie për ekzekutim. Planifikuesi afatgjatë ose planifikuesi i procesorit (ang. CPU scheduler)
bënë zgjedhjen mes punëve në memorie dhe ia jep procesorin njërës prej tyre.
Dallimi primar mes këtyre dy planifikuesve është frekuenca e ekzekutimit të tyre.
Planifikuesi afatshkurtër duhet të bëjë zgjedhjen mes proceseve mjaft shpesh. Proceset zakonisht
ekzekutohen disa milisekonda deri sa të paraqesin kërkesën për hyrje-dalje. Planifikuesi
afatshkurtër zakonisht ekzekutohet njëherë në 10 milisekonda. Për shkak të intervalit shumë të
shkurtë ndërmjet dy ekzekutimeve planifikuesi i tillë duhet të jetë shumë i shpejtë. Nëse
ekzekutimi i tij zgjatë 1 milisekondë atëherë përafërsisht 1/(10+1) = 9% të kohës shpenzohet
vetëm për planifikimin e punëve.
Planifikuesi afatgjatë ekzekutohet më rralë. Ndërmjet paraqitjeve të punëve të reja në
sistem mund të kalojnë edhe disa minuta. Planifikuesi afatgjatë kontrollon shkallën e
multiprogramimit në sistem (numrin e proceseve në sistem). Nëse shkalla e multiprogramimit
është stabile atëherë numri mesatar i punëve që paraqiten në sistem është i njejtë me numrin
mesatar të punëve që dalin nga sistemi. Kjo na mundëson që planifikuesin afatgjatë ta
ekzekutojmë atëherë kur ndonjë punë del nga sistemi. Për arsye se ekzekutohet shumë më rralë se
planifikuesi afatshkurtë, ekzekutimi i planifikuesit afatgjatë mund të zgjatë më shumë.
Për planifikuesin afatgjatë është me rëndësi që në memorie të krijojë përzierje të mirë të
punëve (ang. job mix). Sikur të gjitha punët që duhet të ekzekutohen të jenë të orientuara më
shumë kah hyrja-dalja, rreshti i proceseve të gatshme do të jetë të shumtën i zbrazët e planifikuesi
afatshkurtë nuk do të ketë punë. Nëse të gjitha punët do të jenë të orientuara në angazhimin
intenziv të njësisë qendrore, atëherë rreshtat e njësive do të jenë të zbrazët. Në të dy rastet sistemi
do të jetë i pabalancuar mirë. Për këtë arsye, përzierja e mirë e punëve të orientuara kah hyrja-
dalja e të dhënave dhe e punëve me llogaritje intenzive, rrit efikasitetin e punës së kompjuterit.
Disa sisteme operative nuk e kanë planifikuesin afatgjatë ose ai kryen një numër shumë të
kufizuar të funksioneve. Të tilla sisteme janë time-sharing sistemet. Te këto sisteme çdo punë që
paraqitet vendoset menjëherë në memorie. Stabiliteti i sistemeve të tilla varet nga kufizimet fizike
të sistemit (zakonisht numri i kufizuar i termanaleve). Nuk është i rralë rasti që për shkak se
performansat e sistemit bijnë dukshëm për shkak të numrit të madh të punëve që ndodhen në
sistem, disa shfrytëzues ta ndërprejnë punën. Kjo, në anën tjetër, përmirëson kushtet e punës
shfrytëzuesve më të durueshëm.
Disa sisteme kanë edhe planifikuesin afatmesëm. Ky planifikues është i shpeshtë në
sistemet me memorie virtuale dhe time-sharing sisteme. Është vërejtur se, me qëllim të
përmirësimit të performansave të sistemit, është e dobishme që ndonjërin nga proceset që
konkurojnë për procesor ta largojmë përkohësisht nga memoria, duke zvogluar me këtë rast
shkallën e multiprogramimit. Ky operacion është i njohur si shkëmbim (ang.swaping). Shkëmbimi
mund të bëhet për të përmirësuar përzierjen e punëve në memorie ose për arsye se kërkesat për
memorie të parashtruara nga proceset e kërkojnë këtë.
62
Element tjetër me rëndësi është dispeçeri (ang.dispatcher). Dispeçeri është ai modul që
në fakt ia dorëzon kontrollin mbi procesorë procesit të zgjedhur nga planifikuesi afatshkurtër. Ky
funksion nënkupton mbushjen e regjistrave të kompjuterit me vlerat nga blloku kontrollues i
procesit, kalimin e kompjuterit në modin e shfrytëzuesit, dhe kërcimi në lokacionin e duhur për
vazhdim të ekzekutimit të procesit. Dispeçeri duhet të jetë maksimalisht i shpejtë.
4.3.1 Kriteriumet
Algoritmet e ndryshme kanë cilësi të ndryshme dhe mund të favorizojnë një klasë të
proceseve në raport me një tjetër. Për të zgjedhur algoritmin e dëshiruar duhet shqyrtuar mirë
cilësitë e tij.
Për krahasimin e algoritmeve përdoren kritere të ndryshme. Varësisht se cilat
karakteristika i marrim parasysh në caktimin e algoritmit më të përshtatshëm mund të kemi
rezultate të ndryshme në caktimin e algoritmit më të mirë. Sipas disa kriteriumeve një algoritëm
mund të jetë më i mirë se tjetri. Nëse zgjedhim kriteriume tjera situata mund të ndryshojë. Kriteret
e përdorura janë:
Shfrytëzimi i njësisë qendrore. Nëse njësia qendrore është e shtrenjtë, qëllim kryesor do
të jetë shfrytëzimi intensiv i saj. Shkalla e shfrytëzimit të njësisë qendrore sjellet prej 40% te
sistemet e ngarkuara lehtë deri në 90% te sistemet e përdorura shumë.
Rendimenti (ang. throughput). Një masë për vlerësimin e algoritmeve është numri i
punëve të kryera në njësi të kohës, që do ta quajmë rendiment.
Koha e gjithëmbarshme për kryerjen e punës. Nga këndvështrimi i punës së caktuar
është më rëndësi të dihet sa është e gjatë koha prej momentit të paraqitjes së punës në sistem deri
në momentin e përfundimit të ekzekutimit të saj. Kjo kohë paraqet shumën e kohës së kaluar
duke pritur për tu lexuar në memorie, kohën e kaluar në rresht, kohën e ekzekutimit dhe kohën
për kryerjen e hyrje-daljes. Mund ta emrojmë edhe si kohë e qëndrimit (në sistem). Shprehja
angleze është turnaround time.
Koha e pritjes. Algoritmi i planifikimit nuk ndikon efektivisht në kohën që procesi i
kalon duke u ekzekutuar ose duke kryer operacionet e hyrje-daljes. Algoritmi në fakt ndikon në
kohën që procesi e kalon në rreshtin e proceseve të gatshme. Pra, në vend se ta marrim në
konsiderim kohën e qëndrimit mund ta shqyrtojmë kohën e pritjes për çdo proces.
Koha e përgjegjes. Në sistemet interaktive koha e qëndrimit nuk është kriteriumi më i
mirë. Shpesh procesi mund të gjenerojë rezultate e pas kësaj të vazhdojë punën për të krijuar
rezulatate të reja, në ndërkohë që rezultatet e para ia dërgon shfrytëzuesit. Kjo na bjen deri te
kriteri i ri, që paraqet kohën e kaluar prej paraqitjes së kërkesës deri te përgjegjja e parë e sistemit
dhënë shfrytëzuesit. Kjo kohë, e quajtur koha e përgjegjes, paraqet kohën që nevojitet që të
kalojë deri sa të fillojë dhënja e përgjegjjës në kërkesë e jo tërë kohën e nevojshme për dhënjen e
kësaj përgjegjeje.
Njëhërë pasi ta kemi zgjedhë kriterin për krahasimin e algoritmeve do të tentojmë që atë
ta optimalizojmë. Me këtë rast, do të kërkojmë të maksimalizojmë shfrytëzimin e procesorit dhe
rendimentin duke minimalizuar kohën e qëndrimit, kohën e pritjes dhe kohën e përgjigjes. Në disa
raste do të tentohet që të optimalizohet vlera mesatare e të gjithë këtyre kritereve. Por, ka raste
63
kur qëllimi do të jetë që njërit nga kriteret ti jepet përparësi ndaj tjerëve. Lidhur me këtë,
zakonisht tentohet që të minimalizohet sa është e mundur koha e përgjegjes.
Kur flasim për kohën e përgjegjes, ndoshta është më me rëndësi, që në sistemet
interaktive të minimalizojmë variancën në kohën e përgjegjes se sa kohën mesatare të përgjegjes.
Është më e dëshirueshme që sistemi të ketë kohë të arsyeshme dhe të parashikueshme të
përgjegjes, se sa të ketë kohë mesatare më të vogël të përgjegjes, por që vuan nga variancat e
mëdha prej një përgjegjeje në tjetrën.
Për të analizuar algoritmet e ndryshme është e nevojshme të marrim me qindra punë,
secila prej të cilave përmbanë poashtu me qindra cikluse të procesorit dhe njësive hyrëse-dalëse.
Për të thjeshtuar analizën do të marrim se punët përbëhen vetëm nga një breshëri e procesorit. Si
kriter të vlerësimit të algoritmit do të marrim kohën e qëndrimit të procesit, pra kohën që do të
nevojitet për planifikimin dhe ekzekutimin e punëve.
Koha e qëndrimit të tyre në sistem do të jetë: 24 njësi kohore për punën 1, 27 njësi për punën 2
dhe 30 njësi për punën 3. Koha mesatare e qëndrimit do të jetë:
(24+27+30)/3 = 27.
Sikur punët të arrinin në renditjen 2, 3, 1 atëherë diagrami i Ganttit do të duket:
Koha e qëndrimit për punën 2 do të jetë 3 njësi, për punën 3 - 6 njësi dhe për punën 1 - 30 njësi.
Kjo jep kohën mesatare të qëndrimit:
(3+6+30)/3 = 13
që është dukshëm më pak.
Të marrim rastin kur në sistem kemi një punë të orientuar në llogaritje intenzive dhe
shumë punë të orientuara në hyrje-dalje. Gjatë ekzekutimit të punëve mund të vijmë deri te kjo
situatë. Puna e orientuar në shfrytëzimin e procesorit do të vijë në pronë të procesorit dhe do ta
64
mbajë. Gjatë kësaj kohe të gjitha punët hyrëse-dalëse do të kryhen dhe do të vendosen në rreshtin
e proceseve të gatshme. Derisa këto punë presin në rreshtin e proceseve të gatshme, njësitë
hyrëse-dalëse do të presin pa punë. Pasi ta ketë kryer shfrytëzimin e procesorit, puna e orientuar
kah shfrytëzimi i procesorit do të fillojë operacionet hyrëse-dalëse. Në ndërkohë të gjitha punët e
orientuara kah hyrja-dalja do të kryejnë shfrytëzimin e tyre të procesorit i cili edhe ashtu zgjatë
një kohë të shkurtë dhe do të vendosen përsëri në rreshtin e njësive. Në këtë kohë procesori
mbetet i pashfrytëzuar. Procesi i orientuar në llogaritje do të kthehet përsëri në rreshtin e
proceseve të gatshme dhe do ta fitojë procesorin. Përsëri do të vijmë në situatën kur grupi i
proceseve të orientuara kah hyrja-dalja do të pret në rresht të proceseve të gatshme. Kjo mënyrë
e punës me këtë lloj të punëvë në sistem shkakton paraqitjen e efektit të konvojit. Ky efekt pra,
paraqitet kur grupi i proceseve pret që një proces i gjatë të kryej shfrytëzimin e procesorit.
Rezultat i kësaj është shfrytëzimi i dobët i procesorit dhe njësive hyrëse-dalëse.
Pas llogaritjes del se koha mesatare e qëndrimit të punëve në sistem është 13 njësi kohore.
Algoritmi Së-pari-puna-më-e-shkurtë është algoritmi që jep rezultat më të mirë në
pikëpamje që jep kohë mesatare minimale të pritjes, për grupin e dhënë të punëve. Aktivizimi i
punës së shkurtë para asaj të gjatë zvoglon më shumë kohën e pritjes së punës së shkurtë se sa
rritë kohën e pritjes së punës më të gjatë. Kjo zvoglon kohën mesatare të pritjes.
65
planifikuesi afatshkurtër (planifikimi i punës së procesorit) ky algoritëm nuk mund të përdoret.
Një zgjedhje e këtij problemi është që algoritmi Së- pari-puna-më-e-shkurtë të aproksimohet me
algoritëm te i cili në vend të punës më të shkurtë, e cila nuk mundet asesi të dihet paraprakisht, si
kriter për zgjedhje të përdoret kohëzgjatja e parashikuar e punës. Mund të supozojmë me mjaft
siguri se breshëria e ardhshme e procesorit, për punën e caktuar do të jetë në kohëzgjatje e afërt
me kohëzgjatjen e breshërive paraprake. Në këtë mënyrë duke llogaritur kohëzgjatjen e pritur të
breshërisë së ardhshme mund ta zgjedhim punën me breshëri të parashikuar më të shkurtë.
Kohëzgjatja e pritur e breshërisë së ardhshme llogaritet si mesatare eksponenciale e
kohëzgjatjeve të breshërive paraprake. Të marrim se tn është kohëzgjatja e breshërisë së n-të.
Zgjatjen e breshërisë së ardhshme të n+1-të, τn+1 do ta llogarisim me:
τn+1 = αtn + (1-α)τn
Kjo formulë paraqet mesataren eksponenciale. tn paraqet informatën tonë të fundit, ndërsa αn
ruan historinë e kohëzgjatjeve të breshërive paraprake. Parametri α kontrollon peshën e historisë
më të afërt ose më të largët. Nëse α = 0 atëherë historia më e vonshme nuk luan kurrfarë roli
(τn+1=τn, kushtet momentale konsiderohen si kaluese). Nëse α = 1 atëherë τn+1=tn, që do të thotë se
mirret parasysh vetëm informata për kohëzgjatjen e breshërisë së fundit. Historia konsiderohet e
vjetër dhe irelevante. Që historia e vonshme dhe ajo më e hershme të trajtohen më barabartë
merret se α = 1/2. τ0 iniciale mund të konsiderohet si konstante ose mesatare e përgjithshme e
sistemit. Nëse për τn përdorim shprehjen e plotë atëherë kemi:
τn+1 = αtn + (1-α)αtn-1 + ... + (1-α)jαtn-j + ...
Pasi edhe α edhe (1 - α) janë më pak se 1 çdo kufizë e ardhshme ka peshë më të vogël se kufiza
paraprake.
66
4.3.4 Prioriteti
67
Planifikimi prioritar mund të jetë poashtu me përjashtim ose pa përjashtim. Kur një proces
të arrijë në rreshtin e proceseve të gatshme prioriteti i tij do të krahasohet me prioritetin e procesit
që është momentalisht duke u ekzekutuar. Algoritmi me përjashtim do t'ia merr procesorin
procesit që është duke u ekzekutuar, ndërsa algoritmi pa përjashtim vetëm do ta vendosë
procesin e ardhur rishtas në krye të listës së proceseve të gatshme dhe do të vazhdojë
ekzekutimin e procesit që ka qenë duke ekzekutuar.
Algoritmet pa përjashtim janë të padëshirueshme në time sharing sistemet operative. Te
këto sisteme është e rëndësishme që çdo shfrytëzues ta fitojë intervalin e vet të shfrytëzimit të
procesorit në kohë të pritur. Çdo mbajtje e tepruar procesorit nga ana e ndonjërit proces do të
shkatronte idenë e punës së këtyre sistemeve.
Të marrim si shembull këtë rast:
Puna Koha e arrdhjes Kohëzgjatjë e breshërisë
1 0 8
2 1 4
3 2 9
4 3 5
Algoritmi me përjashtim do të jep renditjen e ekzekutimit të proceseve të dhënë si në figurën
vijuese.
Procesi 1 është startuar në momentin 0 pasi ai është i vetmi proces në sistem. Me ardhjen
e procesit 2, algoritmi do të ndërprej ekzekutimin e tij për arsye se atij i kanë mbetur 7 njësi
kohore për ekzekutim që është më shumë se sa i duhen procesit 2 që i ka 4 njësi kohore. Ardhja e
procesit 3 nuk do të ndryshojë asgjë për arsye se kohazgjatja e breshërisë së tij është më e madhe
se koha e mbetur për ekzekutimin e procesit 2. Me të kryer të procesit 2 do të startohet procesi 4
i cili ka ardhë në ndërkohë por, ka kohëzgjatje më të vogël të breshërisë së procesorit. Pasi të
kryhet ekzekutimi i procesit 4 do të vazhdohet ekzekutimi i procesit 1, e me të kryer të tij do të
ekzekutohet procesi 3 i cili edhepse ka ardhur para procesit 4 është dashur të presë. Koha
mesatare e qëndrimit për këtë rast është ((17-0) + (5-1) + (26-2) + (10-3))/4 = 52/4 = 13.
Varianta pa përjashtim jep për kohë mesatare të qëndrimit vlerën 14,25.
68
tajmerin që të shkatojë ndërprerje pas kalimit të kuantumit kohor dhe e starton procesin. Mund të
paraqiten dy raste. Rasti i parë është kur breshëria e procesorit është më e shkurtë se kuantumi
kohor. Në këtë rast procesi e lëshon vetë procesorin për shkak të kërkesës për operacion hyrës-
dalës ose për shkak të përfundimit të ekzekutimit.
Rasti i dytë paraqitet kur kohëzgjatja e breshërisë është më e madhe se kuantumi kohor.
Në këtë rast porsa të skadojë kuantumi i definuar kohor, tajmeri do të shkaktojë ndërprerje.
Regjistrat e procesit të ndërprerë do të ruhen në bllokun kontrollues të procesit, ndërsa procesi
do të vendoset në fund të rreshtit të proceseve të gatshme. Pas kësaj planifikuesi i proceseve do të
zgjedh procesin e ri që do ta ekzekutojë dhe do t'ia jep kuantumin e definuar kohor.
Nëse marrim grupin e shqyrtuar më parë të punëve:
Puna Kohëzgjatja e breshërisë
1 24
2 3
3 3
Për kuantum kohor prej katër njësive kohore do të fitojmë rrjedhën proceseve të treguar më
poshtë.
Procesi i parë do të fitojë 4 njësitë e para kohore. Pasi atij i nevojiten edhe 20 njësi tjera,
ai do të përjashtohet pas kuantumit të parë kohor. Procesorin do ta fitojë procesi 2, që do të
përfundojë ekzekutimin e tij, pasi zgjatë më pak se kuantumi i definuar kohor. Në vazhdim
procesori do ti jepet procesit 3 i cili poashtu do të përfundojë ekzekutimin e tij para se të skadojë
kuantumi i tij kohor. Pas kësaj, procesori do ti jepet përsëri procesit 1. Ekzekutimi i procesit 1 do
të ndërprehet çdoherë pas kalimit të kuantumin kohor. Mirëpo, nëse në rreshtin e proceseve të
gatshme nuk do të ketë procese tjera ai përsëri do ta fitojë procesorin për të vazhduar
ekzekutimin deri sa të përfundojë. Koha mesatare e qëndrimit është 47/3 = 16.
Në këtë lloj të algoritmit asnjë procesi nuk i jepet procesori për kohë që është më e gjatë
se kuantumi kohor. Nëse breshëria e procesorit është më e gjatë se kuantumi kohor, procesi do të
përjashtohet dhe do të vendoset në rreshtin e proceseve të gatshme. Planifikimi rrethor është
algoritëm tipik me përjahtim.
Nëse në rreshtin e proceseve të gatshme ka n procese, e kuantumi kohor është q njësi,
atëherë çdo proces e fiton 1/n-tën e kohës së procesorit në intervale me kohëzgjatje prej
maksimalisht q njësi. Asnjë proces nuk duhet të presë më shumë se (n-1)*q njësi kohore deri sa të
fitojë kuantumin e ri kohor. Nëse p.sh. në rresht janë 5 procese me kuantum kohor prej 20 milise
kond atëherë çdo proces do të fitojë maksimalisht deri 20 milisekond të çdo 100 milisekondëve të
punës së kompjuterit.
Performansat e algoritmit rrethor varen shumë nga zgjatja e kuantumit kohor. Nëse kjo
kohë nuk është e kufizuar ky algoritëm shëndrrohet në algoritmin I-pari-që-vjen-i-pari-shërbehet.
Nëse ky kuantum është shumë i shkurtë (të marrim 1 mikrosekond), algoritmi rrethor shëndrohet
në algoritëm të quajtur ndarje e procesorit dhe teoretikisht duket thuase n procese e kanë
procesorin e vet që punon me 1/n-tën e shpejtësisë së procesorit real.
Nga ana programore paraqiten tjera probleme. Në fund të çdo kuantumi kohor paraqitet
ndërprerja e gjeneruar nga tajmeri. Përpunimi i kësaj ndërprerjeje do të ketë si pasojë ruajtjen e
regjistrave për procesin e vjetër dhe leximin e regjistrave për procesin e ri. Kjo detyrë është e
njohur si shkëmbim i kontekstit. Shkëmbimi i kontekstit paraqet humbje të pastër të kohës. Kjo
kohë do të ndryshojë prej një kompjuteri në tjetrin dhe do të varet nga shpejtësia e memories,
69
numri i regjistrave dhe ekzistenca e instruksionit special për ruajtjen apo leximin e njëkohëshëm të
të gjitha regjistrave. Zakonisht ky shkëmbim i kontektit zgjatë 10 deri 100 mikrosekond.
70
Fig.4.16 Koha mesatare e qëndrimit ndryshon me kuantumin kohor
Nëse punët që kryhen në kompjuterë mund të klasifikohen lehtë, atëherë është e mundur
të definohet një lloj i ri i algoritmit. Ky klasifikim zakonisht bëhet në punë interaktive dhe batch
aplikacione. Këto dy lloje të punëve kanë kërkesa të ndryshme në pikëpamje të kohës së
përgjegjes, që mundëson ekzistimin e algoritmeve të ndryshme për secilin grup. Për shkak të
natyrës së vet, punët interaktive kanë prioritet më të lartë, krahasuar me batch punët që zakonisht
ekzekutohen në prapavijë.
Algoritmi më shumë rreshtësh i planifikimit e ndanë rreshtin e proceseve të gatshme në
rreshta të veçantë. Punët vendoset në njërin nga rreshtat ekzistues në bazë të cilesive të veta, siç
janë p.sh. kërkesat për memorie, ose lloji i punës. Çdo rresht e ka algoritmin e vet të planifikimit.
Nëse punët i kemi ndarë në grupe si më lartë atëherë është e mundshme që për njërin rresht (të
punëve interaktive) të përdorim algoritmin rrethor, e për tjetrin rresht (të batch punëve)
algoritmin I-pari-që-vjen-i-pari-shërbehet.
71
Fig.4.17 Planifikimi me ndihmën e më shumë rreshtave
72
I-pari-që-vjen-i-pari-shërbehet.
4.3.8 Rreshtat shumënivelësh me riveprim
73
shfrytëzuesin, do të fitojnë relativisht shpejt procesorin, do të ekzekutojnë ato pak instruksione që
zakonisht i kanë dhe do të vazhdojnë hyrje-daljen. Punët që shfrytëzojnë shumë procesorin do të
kenë prioritetin më të ultë.
Planifikuesi shumë-rreshtësh me riveprim definohet nga këta parametra:
- Numri i rreshtave,
- Algoritmi i planifikimit për çdo rresht,
- Nga mënyra e caktimit se kur do të kalojë procesi në rreshtin me prioritet më të lartë,
- Nga mënyra e caktimit se kur do të kalojë procesi në rreshtin me prioritet më të ulte,
- Nga mënyra e caktimit se si do të vendoset se në cilin rresht do të vendoset procesi, kur
për të parën herë të para-qitet në sistem.
Algoritmi që shfrytëzon rreshtat shumënivelësh me riveprim është algoritmi më i
përgjithshëm. Që algoritmi i tillë të jetë me sukses i zbatuar është e nevojshme që me matje të
definohen vlerat optimale të parametrave të tij. Përparësi e këtij algoritmi është mundësia e
deridiku vetëpërshtatjes përzierjes së punëve në sistem me qëllim të arritjes së efektit maksimal.
Zgjedha e algoritmit më të mirë për sistemin e caktuar mund të jetë problem jo edhe aq i
thjeshtë.
Së pari, duhet zgjedhur se cilin kriter do të zbatojmë në zgjedhjen e algoritmit tonë. Siç
kemi thënë këto kritere zakonisht definohen si shfrytëzim i procesorit, kohë e qëndrimit ose si
rendiment. Për ta zgjedhhur algoritmin konkret së pari duhet caktuar se cilit nga këto kritere do ti
japim rëndësi më të madhe, si dhe cilët kritere do ti konsiderojmë më pak të rëndësishme.
Kriteriumet e definuara do të kërkojnë nga algoritmet të plotësojnë kushte të ndryshme. Kushti
mund të jetë i tillë që p.sh. të kërkohet që të maksimalizohet shfrytëzimi i procesorit me kusht që
koha e përgjegjes së sistemit të jetë më e vogël se 1 sekond, ose që të maksimalizohet rendimenti
në atë mënyrë që koha mesatare e qëndrimit të jetë proporcionale me kohën e ekzekutimit.
Pasi ti kemi definuar kriteriumet na mbetet që të vlerësojmë algoritmet e ndryshme me
qëllim të gjetjes së atij që më së miri plotëson kushtet e parashtruara.
Modeli deterministik
Kjo mënyrë e vlerësimit e supozon një ngarkesë punuese për të cilën bënë vlerësimin e
algoritmeve të ndryshme.
Të marrim për shembull se kemi këtë ngarkesë punuese në sistem. Të gjitha punët vijnë
në sistem në momentin 0.
Puna Kohëzgjatja e breshërisë
1 10
2 29
3 3
4 7
74
5 12
Për algoritmet I-pari-që-vjen-i-pari-shërbehet, Së-pari-puna-më-e-shkurtë dhe rrethor (me
kuantum kohor 10 njësi kohore) do të tentojmë të caktojmë kohën mesatare të pritjes.
Për algoritmin I-pari-që-vjen-i-pari-shërbehet do të kemi diagramin vijues:
75
Koha mesatare e pritjes do të jetë 23 njësi kohore.
Si shihet modeli deterministik është i thjeshtë dhe si rezultat jep vlera lehtë të
krahasuseshme. Mirëpo problemi me këtë mënyrë të vlerësimit të algoritmeve është se kërkohet
sasi e madhe e të dhënave të sakta hyrëse, e në anën tjetër rezultatet vlejnë vetëm për këtë rast.
Për këtë shkak modeli deterministik përdoret vetëm për të treguar shembuj që sqarojnë ndonjë
qështje. Mirëpo, nëse modeli përdoret mbi grupe të ndryshme të shembujve mund të na jep një
pasqyrë për sjelljen e përgjithshme të algoritmeve të ndryshme, sjellja konkrete e të cilëve mbi
përzierje të caktuar të punëve mund të analizohet dhe vlerësohet ndamas.
Në përgjithësi, modeli deterministik është shumë specifik për ngarkesën e zgjedhur për të
dhënë vlerësime të përdorshme për shumicën e rasteve. Problem paraqet edhe nevoja e njohjes së
shumë informatave paraprake.
Modelet e rreshtave
76
4.4.2 Simulimet
Për të fituar vlerësim më të saktë për algoritmin e shqyrtuar përdoren shumë shpesh
simulimet. Kjo në vehte përfshin edhe programimin e modelit të kompjuterit. Strukturat
softverike të të dhënave paraqesin pjesët kryesore të sistemit. Simulatori ka variablën e cila
simulon orën dhe me rritjen e vlerës së saj, simulatori modifikon gjendjen e sistemit për të
reflektuar aktivitetin e njësive, proceseve dhe planifikuesit. Gjatë ekzekutimit të simulacionit,
mbledhen statistikat e nevojshme për të treguar performansat e algoritmit.
Të dhënat që i shfrytëzon simulatori mund të gjenerohen në mënyra të ndryshme.
Metodat më të zbatuara përdorin gjeneratorin e numrave të rastit për të gjeneruar procese,
kohëzgjatje të breshërive, kohë të arrdhjes dhe daljes nga sistemi, etj. të gjitha këto në bazë të
distribucioneve të rastit. Këto distribucione mund të definohen matematikisht (distribucioni
uniform, eksponencial, i Poissonit), ose empirikisht. Që distribucioni të definohet empirikisht
duhet bërë matje në sistemin që shqyrtohet. Rezultatet e fituara mund të shfrytëzohen për
definimin e distribuimit aktual të ngjarjeve në sistemin real. Ky distribucion përdoret pastaj për të
udhëhequr simulimin.
Mirëpo, simulimi i udhëhequr nga distribucioni mund të jep rezultate të pasakta, për
shkak të relacioneve mes ngjarjeve të njëpasnjëshme në sistemin real. Distribucionet e ngjarjeve
na tregojnë vetëm se sa herë është paraqitë një ngjarje, e nuk na japin kurrfarë informate se në
çfarë renditje është bërë kjo. Për të korigjuar këtë problem përdoren shiritat e gjurmëve. Shiriti i
gjurmëve krijohet duke përcjellë sistemin real, duke regjistruar sekuencat e ngjarjeve (Fig.4.19).
Kjo sekuencë pastaj përdoret për të udhëhequr simulimin. Shiritat e gjurmëve janë metodë shumë
e mirë për krahasimin e dy algoritmeve në grup identik të ngjarjeve reale. Metoda jep rezultate
shumë të sakta.
77
Fig.4.19 Vlerësimi i planifikuesve të procesit përmes simulimit
Simulimet janë aktivitet që mund të kushtojnë shtrenjtë sepse shpenzojnë shumë kohë të
kompjuterit. Në anën tjetër, përdorimi i shiritave të gjurmëve kërkon shpenzim të sasive të mëdha
të shiritit, për arsye se sa më shumë të dhëna që të përdoren simulimi do të jetë më i suksesshëm e
rezultatet më të sakta. Krijimi i modelit matematikor softverik të kompjuterik mund të
shëndrrohet në problem të vërtetë.
Vëmendjen tonë deri tani ia kemi kushtuar planifikimit të procesorit në sistemin me një
procesorë. Nëse sistemi ka më shumë procesorë problemi i planifikimit bëhet më kompleks.
Ekzistojnë shumë mundësi për zgjidhjen e këtij problemi, por si edhe të sistemi njëprocesorik
mund të definojmë zgjidhjen më të mirë për çdo rast.
Faktor qenësor në shqyrtimin e këtij problemi është lloji i procesorëve të përdorur.
Procesorët mund të jenë identik (sistemi homogjen) dhe të ndryshëm (sistemi heterogjen). Nëse
procesorët janë të ndryshëm opcionet e mundshme do të jenë të kufizuara. Secili procesor e ka
rreshtin e vet të proceseve të gatshme dhe algoritmin e planifikimit. Programet e shkruara për një
procesor do të ekzekutohen vetëm në atë procesor.
Nëse janë në dispozicion më shumë procesorë identik, atëherë, mund të bëhet ndarja e
ngarkesës punuese. Edhe në këtë rast është e mundshme të kemi rreshta të veçantë për secilin
procesor, mirëpo në atë rast mund të ndodhë që ndonjëri prej procesorëve të rrijë i papunë ndërsa
të tjerët të jenë të zënë. Është më e arsyeshme, që në këtë sistem të kemi një rresht unik të
proceseve të gatshme, të cilëve do tu ndahet procesori i cili është momentalisht në dispozicion.
Në sistem me shumë procesorë mund të zbatojmë dy qasje. Njëra qasje nënkupton që çdo
procesorë e shqyrton rreshtin e përbashkët dhe e zgjedh procesin që do ta ekzekutojë. Nëse do të
kemi rastin e tillë pra, kur secili prej procesorëve do ti qaset dhe do të tentojë të ndërrojë
përmbajtjen e strukturave të përbashkëta të të dhënave, duhet të jemi të kujdesshëm në
programimin e punës së atij procesori. Duhet të jemi të sigurt, që dy procesorë nuk do ta zgjedhin
njëkohësisht të njejtin proces për ekzekutim, dhe se proceset nuk do të humben nga rreshti. Qasja
tjetër e eliminon këtë problem duke caktuar njërin procesorë si planifikues për procesorët tjerë,
duke imponuar kështu strukturën master/slave në sistem.
78
5 Udhëheqja me memorie
Memoria është pjesë qenësore e sistemit kompjuterik. Edhe procesori edhe sistemi i
hyrje-daljes komunikojnë me memorien. Memoria është fushë e madhe e fjalëve ose bajtëve që
kanë secili adresën e vet. Komunikimi me procesor dhe sistem hyrës-dalës arrihet me ndihmën e
sekuencave të leximit dhe shkruarjes së të dhënave në adresa specifike. Njësia qendrore i merr të
dhënat nga memoria dhe i ruan të dhënat në memorie.
79
Fig.5.2 Hapat e përpunimit të programit të shfrytëzuesit
80
kontroll absolut mbi të.
81
Fig.5.4 Monitori rezident
82
Fig.5.5 Mbrojtja hardverike e adresave për monitorin rezident
5.3.2 Relokacioni
83
simbolike janë lidhur me adresat fizike me ndërmjetsimin e kufirit, atëherë këto adresa do të jenë
jovalide nëse kufiri ndëron. Pra, rrjedh se kufiri nuk bën të ndërrohet gjate ekzekutimit të
programit. Mirëpo, në disa raste është e dëshirueshme që të ndërrojmë madhësinë e monitorit në
memorie (lidhur me këtë edhe kufirin mes memories monitorike dhe memories së programeve të
shfrytëzuesit) gjatë ekzekutimit të programit. Monitori mund të përmbajë p.sh. kodin dhe të
dhënat për drajverët e njësive. Nëse ky drajver ose ndonjë pjesë tjetër e sistemit operativ nuk
është shpesh e përdorur, s'ka kuptim të mbahet tërë kohën në memorie, për arsye se atë hapësirë
mund ta përdorim për qëllime tjera. Kjo pjesë e kodit njihet me emrin pjesa tranziente e
monitorit. Pjesa tranziente e kodit të monitorit do të sjellet në memorie gjatë ekzekutimit të
programit të shfrytëzuesit, nëse për këtë pjesë të kodit paraqitet nevoja.
Ekzistojnë dy mënyra që mundësojnë ndërrimin dinamik të madhësisë së monitorit. Një
mënyrë e përdorur te sistemet e hershme operative për kompjuterët PDP-11 është sjellja e
programeve të shfrytëzuesit në memorien e epërme duke filluar prej majës për të vazhduar kah
kufiri e jo prej kufirit kah memoria e epërme (Fig.5.6). Përparësia e kësaj mënyre është se si
monitori ashtu edhe programi i shfrytëzuesit mund të zgjerohen sipas nevojës kah hapësira e lirë e
cila gjendet në mes.
84
Fig.5.7 Relokimi dinamik me anë të regjistrit të relokacionit
Duhet theksuar këtu se shfrytëzuesi kur nuk i sheh adresat reale fizike. Shfrytëzuesi mund
të krijojë treguesin në adresën 246, ta ruajë në memorie, të manipulojë me të, ta krahasojë me
adresat tjera, gjithnjë si 246. Vetëm në momentin kur të përdoret si adresë memorike (gjatë
leximit ose shkruarjes në memorie), vlera e tij do të ndryshojë duke marr parasysh vlerën e
regjistrit të bazës. Programi i shfrytëzuesit ka të bëjë me adresa logjike. Shndërrimin e adresave
logjike në adresa fizike e bën hardveri për mapimin e memories.
Për këtë hardver, ndërrimi i kufirit ka nevojë vetëm për ndërrimin e përmbajtjes së
regjistrit të bazës dhe zhvendosjen e gjithë memories së shfrytëzuesit në adresa të reja që do të
pasqyrojnë vlerën e re të kufirit. Kjo mënyrë e punës kërkon që të kopjohen sasi të konsiderue
shme të memories, por në anën tjetër lejon që kufiri të ndërrohet kurdoqoftë.
Në këtë rast kemi dy tipe të ndryshme të adresave: adresat logjike në brezin prej 0 deri në
max dhe adresat fizike në brezin prej R+0 deri R+max për vlerë të kufirit R. Shfrytëzuesi
gjeneron adresa logjike në brezin 0 deri max dhe mendon se programi i tij ekzekutohet në këto
lokacione. Sistemi operativ mund ti qaset memories fizike drejtpërdrejt në modin e supervisorit.
Të gjitha informatat e përcjellura nga programi i shfrytëzuesit (siç janë p.sh. adresat e baferëve në
thirrjet sistemore) sistemit operativ, duhet në mënyrë eksplicite të modifikohen para përdorimit.
Kjo posaçërisht vlen për adresat e njësive hyrëse-dalëse. Shfrytëzuesi këtyre njësive do tu jep
adresa logjike të cilat duhet të shndërrohen në adresa fizike para se të përdoren.
Kuptimi i hapësirës logjike adresore e cila mapohet në hapësirën adresore fizike të
veçantë është qenësor për problematikën e këtij kapitulli.
5.4 Zëvendsimi
Skema e përmendur e punës së kompjuterit na bënë të mendojmë së është fjala për sistem
njëshfrytëzues (ang. single-user). Mirëpo, kjo mënyrë e ndarjes së memories mes monitorit dhe
programit të shfrytëzuesit është përdorë edhe në time-sharing sistemet e para. Këto sisteme e
kanë përdorë monitorin rezident, ndërsa memorien tjetër ia kanë lënë në dispozicion shfrytëzuesit
momental. Në momentin kur sistemi ka kaluar në shfrytëzuesin tjetër, përmbajtja momentale e
memories së shfrytëzuesit është kopjuar në njësi (hapësirë) përkrahëse (ang. backing store, shq.
85
njësi kompjuterike, zakonisht disk, që shërben për të përkrahur ose bërë të mundur ekzekutimin e
ndonjë operacioni), ndërsa në memorie është sjellë shfrytëzuesi i ri. Kjo operacion quhet
zëvendsim (ang. swapping).
Zëvendsimi kërkon njësi përkrahëse. Njësi përkrahëse është zakonisht disku. Disku duhet
të jetë mjaft i madh që të mund të ruajë kopjet e të gjitha imazheve memorike të të gjithë shfrytë
zuesve dhe duhet të sigurojë qasje direkte të gjithë këtyre imazheve memorike. Rreshti i
proceseve të gatshme përmban të gjitha proceset, imazhet memorike të të cilëve, ndodhen në
njësinë përkrahëse dhe që janë të gatshëm të ekzekutohen. Variabla e veçantë sistemore na tregon
se cili proces është momentalisht në memorie. Secilën herë që planifikuesi i procesorit të vendosë
të ekzekutojë një proces, ai do ta thërret dispeçerin. Dispeçeri do të kontrollojë se a ndodhet ky
proces në memorie. Nëse nuk ndodhet, dispeçeri do të zëvendsojë procesin në memorie me një
proces tjetër të zgjedhur nga planifikuesi. Pas kësaj do ti mbush regjistrat e kompjuterit me
përmbajtje të nevojshme për këtë proces dhe do t'ia dorëzojë kontrollin mbi kompjuter.
86
8ms + 20KW/250KW/s = 88ms
Pasi do të duhet që programin ta sjellim në memorie dhe ta këthejmë në disk, koha totale për
zëvendsim do të zgjasë 176ms.
Që shfrytëzimi i procesorit të jetë i lartë, koha e zëvendsimit duhet të jetë dukshëm më e
vogël se kuantumi kohor (koha e ekzekutimit të procesit). Nëse përdorim planifikimin rrethor të
procesorit atëherë kuntumi kohor duhet të jetë dukshëm më i madh se p.sh 176ms.
Koha më e madhe e shpenzuar për zëvendsim është koha e transferit. Koha e
përgjithshme e transferit është proporcionale me sasinë e memories që zëvendsohet. Nëse
programi është p.sh. më i shkurtë se 20kW, atëherë koha e transferit do të jetë më e vogël se
p.sh. 176ms, nëse është fjala për të njejtin sistem. Për këtë arsye, është e nevojshme që monitori
të jetë i informuar se sa memorie është programi momentalisht duke shfrytëzuar, e jo vetëm sa do
të mund të shfrytëzonte. Kjo do të mundësonte që të zëvendsohet vetëm ajo pjesë e memories që
nevojitet, duke shkurtuar kohën e nevojshme për transfer. Që kjo të realizohet, procesi me
kërkesa të ndryshueshme të memories gjatë ekzekutimit të vet, duhet që këto kërkesa për
memorie ti kënaq duke ekzekutuar thirjet sistemore për kërkimin (ang. Request Memory) dhe
lirimin e memories (ang. Release Memory).
Efekti i zëvendsimit mund të rritet duke përmirësuar cilësinë e njësisë përkrahëse. Rritja e
shpejtësisë së punës së këtyre njësive mund të përmirësohet me zvoglimin e kohës së vonesës dhe
rritjen e shpejtësisë së transferit të të dhënave.
87
Duhet theksuar në këtë rast se, pasi që procesi që është duke u ekzekutuar momentalisht
ta liroj procesorin, duhet ta bartim procesin e ardhshëm nga baferi 2 në regjionin e shfrytëzuesit,
para se ai të fillon ekzekutimin. Procesi që momentalisht ndodhet në regjionin e shfrytëzuesit
duhet poashtu të zhvendoset në njërin prej baferëve për zëvendsim. Sikur kjo të mos bëhej
atëherë programin në baferin 2 do të mund ta ekzekutonim vetëm me zhvendosjen e kufirit
(Fig.5.10). Procesi paraprak (në regjionin e shfrytëzuesit) do të jetë në atë rast i ekspozuar
modifikimeve jo të rregullta nga ana e procesit në baferin 2. Kjo na shtyn që të bëjmë zëvendsimin
memorie-memorie.
Kjo qasje është ka disa kufizime që do të paraqiten nëse përdoren njësi shumë të shpejta
të disqeve. Fjala është për njësi që kanë shkallën e transferit të barabartë me shpejtësinë e
memories operative. Në këtë rast nuk do të na mbeteshin cikluse memorike që do ti shfrytëzonte
procesori. Puna e tij gjatë këtij transferi do të ndalej tërësisht që do të pamundsonte përputhjen
kohore të zëvendsimit dhe ekzekutimit të procesit.
Ekzistojnë edhe disa çështje që kufizojnë mundësitë e zëvendsimit. Nëse dëshirojmë ta
zëvendsojmë një proces duhet të jemi të sigurt se ai është plotësisht i papunë (joaktiv). Problem i
veçant janë kërkesat e procesit për hyrje-dalje. Nëse procesi është duke pritur për të kryer
operacionin e hyrje-daljes, atëherë mund të hamendemi që procesin ta zëvendsojmë. Mirëpo, nëse
operacioni i hyrje-daljes është duke iu qasur në mënyrë asinkrone baferëve të hyrje-daljes në
memorien operative, atëherë procesi nuk bën të zëvendsohet. Të marrim parasysh situatën kur
kërkesa për hyrje-dalje është vendosur në rresht për arsye se njësia hyrëse-dalëse ka qenë e zënë.
Nëse procesin 1 e zëvendsojmë me procesin 2, operacioni i hyrje-daljes mund të tentojë ta
shfrytëzojë memorien që tani i takon procesit 2. Një zgjidhje e këtij problemi është që asnjëherë të
mos e zëvendsojmë procesin që ka kërkesa të parealizuara për hyrje-dalje. Zgjidhja tjetër e këtij
problemi parasheh kryerjen e operacionit të hyrje-daljes mes njësisë hyrëse-dalëse dhe baferëve të
sistemit operativ. Transferi mes baferëve sistemor dhe memories së shfrytëzuesit do të bëhet kur
procesi të sjellet në memorie.
88
5.5 Particionet e shumëfishta
Siç e kemi parë deri tani, është e nevojshme që kodi dhe të dhënat në një regjion të
mbrohen nga programi në regjionin tjetër. Na duhet pra, që të mbrojmë hapësirën memorike para
dhe pas programit që ekzekutohet. Kjo mbrojtje realizohet me shfrytëzimin e dy regjistrave
(Fig.5.11).
89
Këta dy regjistra tregojnë kufirin e poshtëm dhe të epërm të adresave që mund të
gjenerohen nga programi i shfrytëzuesit. Mund të definohen në njërën nga këto dy mënyra:
Regjistrat e kufirit. Regjistrat e kufirit përmbajnë vlerën më të vogël dhe më të madhe të
adresave fizike të cilave shfrytëzuesi mund t'iu qaset në mënyrë legale.
Regjistrat e bazës dhe limitit. Regjistrat përmbajnë vlerën e adresës më të vogël fizike
dhe kufirit të adresave logjike. Adresat legale të shfrytëzuesit janë në brezin 0 deri limiti.
Relokacioni dinamik i këtyre adresave bëhet në adresat fizike prej baza deri baza + limiti.
Hardveri për këto dy zgjidhje është i ndryshëm. Regjistrat e kufirit kërkojnë relokacionin
statik në kohën e kompajlimit ose sjelljes. Çdo adresë duhet të jetë më e madhe se kufiri i
poshtëm dhe më e vogël se kufiri i epërm. Kur kemi regjistrin bazë dhe regjistrin e limitit çdo
adresë logjike duhet të jetë më e vogël se vlera në regjistrin e limitit. Relokacioni, në këtë rast
dinamik, bëhet duke ia shtuar secilës adresë vlerën në regjistrin bazë. Në memorie dërgohet
adresa e relokuar.
Fig.5.12 (a) Regjistrat e kufirit dhe (b) regjistrat e bazës dhe limitit
90
Në MFT regjionet janë fikse dhe madhësia e tyre nuk ndërron gjatë punës së kompjuterit.
Si shembull për shqyrtimet vijuese do të marrim memorien me kapacitet 32kW, që mund të jetë e
ndarë në regjione të këtyre madhësive:
Monitori rezident 10K
Punët shumë të vogla 4K
Punët mesatare 6K
Punët e mëdha 12K
Nëse p.sh. kemi tri regjione memorike, të madhësisë 2K, 6K dhe 12K, na duhen tri
rreshta R2, R6 dhe R12. Puna që kërkon 5K të memories do të shtohet në fund të rreshtit R6,
puna me kërkesë 10K do të vendoset në rreshtin R12, ndërsa ajo që kërkon 2K do të vendoset në
rreshtin R2. Çdo rresht planifikohet veçanërisht. Pasi secili rresht e ka regjionin e vet memorik
91
nuk kemi konkurencë ndërmjet rreshtave për memorie.
Alternativisht, punët e ardhura në sistem mund ti vendosim në një rresht (Fig.5.14).
Planifikuesi i punëve e zgjedh një punë nga rresti dhe pret që regjioni memorik i kësaj madhësie të
jetë në dispozicion. Të supozojmë se e kemi planifikuesin I-pari-që-vjen-i-pari-shërbehet, rreshtin
e punëve nga figura vijuese dhe regjionet 2K, 6K dhe 12K. Punën 1 do ta vendosnim në regjionin
6K, ndërsa punën 2 në regjionin 2K. Puna e ardhshme i kërkon 3K, që do të thotë se na nevojitet
regjioni 6K. Pasi ky regjion është i zënë me punën 1 duhet të presim derisa puna 1 të kryhet. Me
të përfunduar të punës 1, punës 3 do ti jepet regjioni 6K. Edhepse puna 4 e ka regjionin e lirë në
dispozicion, ajo duhet të presë që planifikuesi ta vendosë në regjionin ku do të ekzekutohet, por
vetëm pasi ti ketë startuar punët që ndodhen para saj në rresht.
Një variantë e kësaj skeme që menjëherë bie në sy tenton që regjionet memorike ti mbajë
gjithmonë të zëna. Kështu, në momentin kur një regjion të jetë në dispozicion, do të kërcejmë
nëpër rreshtin e punëve për të gjetur punën që mund të vendoset në atë regjion. Kjo punë do të
sjellet në memorie, edhepse punë të prioritetit më të lartë (por më të mëdha) janë duke pritur para
saj në rresht. Këto punë të prioritetit më të lartë nuk mund ta shfrytëzojnë regjionin në
dispozicion, pasi kanë kërkesa memorike më të të mëdha. Startimi i punëve më të vogla nuk
ndikon në përparimin e punëve më të mëdha në rreshtin e punëve. Ato edhe ashtu nuk do të
mund të shfrytëzonin regjionin i cili është i lirë në atë moment.
Varianta tjetër e kësaj skeme merret me problemin e pritjes së punës 3 në ndërkohë që
ekziston regjioni i lirë memorik, ai i 12K. Shtrohet pyetja se a duhet vendosur punën 3 në regjinin
12K në të cilin ajo gjithsesi do të mund të ekzekutohej, apo duhet pritur që të lirohet regjioni 6K,
e punën 4 e cila mund të vendoset vetëm në këtë regjion ta startojmë para punës 3. Çka do të
bëjmë në momentin kur puna 4 do të përfundojë? A do ta vendosim në atë regjion ndonjë punë që
do të mund të kryhej edhe në regjion më të vogël apo do ta lëmë regjionin të pashfrytëzuar (të
rezervuar për ndonjë punë më të madhë që mund të arrijë)?
Këto dy mënyra të zgjidhjes së këtij problemi kanë të bëjnë me përcaktimin për mënyrën e
92
qasjes vendosjes së punëve në memorie të njohura si Vetëm-ajo-që-përgjigjet-më-së-miri (ang.
best-fit-only) dhe Ajo-që-përgjigjet-më-së-miri-nga-ato-që-janë-në-dispozicion (ang. best-
available-fit).
Variantë tjetër e MFT-ës fitohet duke shtuar zëvendsimin. Të marrim parasysh se kemi
disa punë që secila veç e veç mund të vendoset në regjionin e dhënë. Atëherë mundemi që këto
punë ti sjellim dhe ti largojmë nga regjioni me anë të zëvendsimit. Të supozojmë se i kemi 4
regjione, ku secili prej tyre e ka algoritmin rrethor të planifikimt të procesorit. Kur të kalojë
kuantumi kohor, procesi që është në regjionin e dhënë memorik do të largohet duke u zëvendsuar
nga procesi tjetër për këtë regjion. Gjatë kësaj kohe planifikuesi i procesorit do t'ia jep jep një
procesi në një regjion tjetër një kuantum kohor për ekzekutim. Kur një proces të përfundojë
ekzekutimin do të zëvendsohet me një proces për të njejtin regjion.
Një nënvariantë e variantës që përdorë zëvendsimin shfrytëzohet në algoritmet e
planifikimit të bazuara në prioritet. Nëse puna me prioritet më të lartë arrin në sistem udhëheqësi i
memories mund ta largojë nga memoria punën me prioritet më të ultë me qëllim të sjelljes dhe
vendosjes së punës me prioritet më të lartë. Kur procesi me prioritet më të lartë të përfundon
ekzekutimin, në memorie do të kthehet procesi me prioritet më të ultë dhe do të vazhdojë
ekzekutimin.
Në MFT puna e cila zëvendsohet do të kthehet përsëri në të njejtin regjion. Ky kufizim
është i imponuar nga mënyra e ndarjes së regjioneve dhe nga mënyra e relokacionit. Nëse
relokacioni bëhet gjatë kohës së kompajlimit ose sjelljes (relokacioni statik), atëherë puna nuk
mund të vendoset në ndonjë regjion tjetër. Nëse përdoret relokacioni dinamik që përdorë çiftin e
regjistrave të bazës dhe limitit, është e mundshme që punën ta kthejmë në ndonjë regjion tjetër.
Siç kemi thënë më parë proceset mund të kërkojnë memorien dhe të lirojnë memorien.
Kjo u mundëson programeve që në mënyrë dinamike të paraqesin kërkesat e tyre për memorie,
bazuar në të dhënat hyrëse, e jo në mënyrë statike. Kjo mundësi mund të shkaktojë probleme në
MFT. Të marrim se procesi që shfrytëzon 4K është i vendosur në regjionin 6K. Procesi mund të
kërkojë memorie dhe të lirojë memorie sa herë të dëshiron me kusht që mos të kalojë kufirin e
regjionit (6K).
Nëse procesi kërkon më shumë se 6K memorie kemi tri zgjidhje të ndryshme:
- Mund ta përfundojmë punën. Nëse kërkojmë nga shfrytëzuesi që të specifikojë kërkesat
maksimale për memorie dhe këtë vlerë e përdorim për zgjedhjen e regjionit memorik, atëherë
kërkesa për edhe më shumë memorie paraqet gabim të ekzekutimit (ang. run-time error shq.
gabim që shfaqet gjatë kohës së ekzekutimit).
- Mund t'ia kthejmë kontrollin programit të shfrytëzuesit me porosi që nuk ka më
memorie. Me të marrur të kësaj porosie, programi i shfrytëzuesit mund të përfundojë ekzekutimin
ose të ndryshojë kërkesat për memorie me qëllim të vazhdimit të ekzekutimit në kuadër të
hapësirës në dispozicion. Shumë algoritme ofrojnë mundësinë e kompromisit hapësirë-kohë. Më
shumë hapësirë i mundëson programit të ekzekutohet më shpejtë, por nuk është e thënë që
programi nuk do të mund të ekzekutohet duke shfrytëzuar më pak memorie, kuptohet më
ngadalë.
- Mund ta (1) largojmë punën, (2) të presim që një regjion më i madh të jetë në
dispozicion, (3) ta sjellim punën në regjionin më të madh dhe (4) të vazhdojmë ekzekutimin. Kjo
zgjidhje është e mundshme vetëm në sistemet ku hardveri ofron përkrahje relokacionit dinamik.
Zgjidhja mund të jetë mjaft e shtrenjtë, por në anën tjetër ofron fleksibilitet maksimal për
programet që gjatë ekzekutimit kanë kërkesa të ndryshme për memorie.
Nëse sistemi operativ është i informuar për sasinë e memories që është duke u shfrytëzuar
nga programi, atëherë edhe koha e nevojshme për zëvendsim të të dhënave mund të zvoglohet.
Nëse programi që ndodhet në regjionin 12K shfrytëzon vetëm 7K, atëherë vetëm 7K duhet të
zëvendsohen.
93
Zgjedhja e madhësisë së regjionit
Fragmentimi i memories
Siç e pamë, problem kryesor i MFT-ës është caktimi i drejtë i madhësisë së regjioneve.
Pasi punët që ekzekutohen kanë kërkesa të ndryshme memorike është e mundshme që edhe asnjë
94
punë të mos e gjejë particionin optimal.
Zgjedhje e këtij problemi është ndryshimi dinamik i madhësisë së regjioneve. Kjo qasje
është e njohur si vendosje në particione të shumëfishta të pandërprera variabile (MVT). Me MVT
do të nënkuptojmë këtë klasë të algoritmeve për udhëheqje me memorie.
Sistemi operativ do të mirëmbajë tabelën e pjesëve të lira dhe të zëna të memories. Në
fillim e tërë memoria është e lirë dhe në dispozicion programeve të shfrytëzuesve. Kjo memorie
kosiderohet si një bllok i lirë i memories ose si vrimë. Kur në sistem të vie një punë dhe të
parashtron kërkesën për memorie, algoritmi do të kërkojë vrimën që do të plotëson këtë kërkesë.
Nëse e gjenë një vrimë të tillë, do t'ia jep programit vetëm pjesën e nevojshme, ndërsa tepricën do
t'ia len në dispozicion kërkesave të ardhshme të programeve tjera.
95
Fig.5.16 Shembull i vendosjes memorike dhe planifikimit të punëve MVT
96
Fig.5.17 Vendosja është e kufizuar në shumëfisha të një madhësie themelore
Kompaktëzimi
97
e mëposhtme, në të cilin rast vrimat prej 10K, 30K dhe 26K janë kompaktëzuar në një vrimë prej
66K.
Fig.5.18 Kompaktëzimi
Kompaktëzimi nuk është gjithnjë i mundur. Nga figura vërehet se punët 3 dhe 4 janë
zhvendosur. Që këto programe të mund të punojnë në adresa të reja të gjitha adresat e krijuara
duhet të ndërrohen. Nëse relokacioni është statik dhe është bërë gjatë kompajlimit ose sjelljes,
kompaktëzimi nuk mund të kryhet. Kompaktëzimi është i mundur vetëm nëse relokacioni është
dinamik, dhe kryhet gjatë ekzekutimit, me përdorimin e regjistrave të bazës dhe limitit.
Nëse adresat rilokohen dinamikisht, relokacioni do të kërkojë vetëm zhvendosjen e
programit dhe të dhënave, e pastaj ndërrimin e regjistrit të bazës për të shprehur adresën e re të
bazës.
Mënyra më e thjesht por edhe më e shtrenjtë e kompaktëzimit është zhvendosja e punëve
kah njëri skaj i memories, që shkakton zhvendosjen e vrimave kah tjetri skaj, duke dhënë në fund
një vrimë të madhe të pandarë.
98
Fig.5.19 Krahasimi i disa mënyrave të ndryshme të kompaktëzimit të memories
Të shikojmë memorien nga Fig.5.19. Nëse e përdorim këtë algoritëm të thjeshtë, duhet ti
zhvendosim punët 3 dhe 4, që do të thotë duhet të zhvendosim 600K. Në vend të kësaj kemi
mundur të zhvendosim punën 4 mbi punën 3 duke zhvendosur kështu 400K ose kemi mundur ta
zhvendosim punën 3 nën punën 4, duke zhvendosur kështu vetëm 200K. Në rastin e fundit, vrima
e madhe ndodhet në mes të memories e jo në skajet e saj. Duhet vërejtur poashtu se nëse rreshti
do të përmbante vetëm punën që kërkon 450K do të mund të plotësonim këtë kërkesë të veçantë
duke e zhvendosur punën 2 diku tjetër (si.p.sh. nën punën 4) Edhepse kjo zgjidhje nuk krijon një
vrimë të madhe të vetme, ajo megjithatë krijon vrimë me madhësi të mjaftueshme për të kënaqur
kërkesën aktuale.
Sistemi operativ SCOPE në kompjuterët CDC 6600 ka përdorë MVT skemën për
udhëheqje të memories me kompaktëzim. Sistemi lejonte që deri në 8 punë të ndodhen
njëkohësisht në memorie. Me të kryer të ekzekutimit të cilido procesi, memoria kompaktëzohej
për të siguruar që memoria e lirë të jetë në një vrimë në fund të memories.
Me MVT mund të kombinohet zëvendsimi. Puna mund të largohet nga memoria në
njësinë përkrahëse dhe të kthehet përsëri në memorie më vonë. Kur puna të largohet nga memoria
hapësira e saj do të lirohet dhe do të përdoret nga ana e ndonjë pune tjetër. Gjatë kthimit të punës
në memorie dallojmë rastet kur përdoret relokacioni statik dhe dinamik. Nëse relokacioni statik
është përdorë puna duhet kthyer në të njejtat adresa që ka okupuar më parë. Kjo mund të ketë si
rrjedhim nevojën që punët tjera të largohen për të liruar hapësirën e zënë. Nëse relokacioni
dinamik është përdorë, puna mund të kthehet në cilëndo vrimë të lirë (nëse nevojitet do të bëhet
kompaktëzimi).
Një qasje kompaktëzimit është që punët që duhet zhvendosur të barten njëherë në njësinë
përkrahëse, e pastaj të kthehen në lokacione tjera memorike. Nëse kodi për zëvendsim është pjesë
e sistemit operativ atëherë sasia e kodit që kryen kompaktëzimin mund të jetë minimale.
Sasinë mesatare të fragmentimit ekstern mund ta zvoglojmë duke zvogluar madhësinë
mesatare të punës. Qasje tjetër është që memorien që e kërkon puna ta ndajmë në dy pjesë.
Kompjuteri PDP-10 i ka dy çifte të regjistrave bazë/limit. Memoria është e ndarë në dysh
me ndihmën e bitit të rendit të lartë të adresës. Memoria e poshtme mund të rilokohet dhe
kufizohet me çiftin 0 të regjistrave, ndërsa memoria e epërme me çiftin 1. Sipas marrëveshjes
99
kompajlerët dhe asemblerët i vendosin konstantet dhe instruksionet në memorien e epërme,
ndërsa variablat në memorien e poshtme. Bitat e mbrojtjes janë të lidhur me secilin çift të
regjistrave dhe mund të sigurojnë që memoria e epërme të përdoret vetëm për lexim. Rregullim i
tillë, mundëson që programet e vendosura në memorien e epërme, (ku ruhen si programe vetëm
për lexim, ang. read-only), të shfrytëzohen nga ana e më shumë shfrytëzuesve, secili prej të cilëve
e ka segmentin e vet në memorien e poshtme.
Kompjuteri UNIVAC 1108 ka rregullim të ngjashëm që bazohet në skemë tjetër të
ndarjes. Procesori i kompjuterit e di se a dëshiron instruksionin apo të dhënat. Në bazë të kësaj ky
kompjuter ka dy çifte te regjistrave bazë/limit: njërin për instruksione e tjetrin për të dhëna. Çifti i
regjistrave bazë/limit i instruksioneve është automatikisht i definuar vetëm për lexim, që
mundëson që programet të mund të shfrytëzohen nga ana e më shumë shfrytëzuesve.
Në të dy rastet me ndarjen e kodit dhe të dhënave dhe relokacionin e veçantë të tyre, e
bëjmë të mundur shfrytëzimin e programeve mes më shumë shfrytëzuesve. Kjo siguron që
memoria të përdoret më efektivisht, për arsye se përjashton nevojën e ekzistencës së më shumë
kopjeve të përmbajtjeve të njejta në memorie (editorëve, kompajlerëve, dhe programeve tjera të
ngjashme) dhe zvoglon fragmentimin.
5.6 Faqëzimi
Fragmentimi i jashtëm paraqitet për arsye se memoria e lirë nuk është e pandarë, por e
copëtuar në shumë blloqe të shpërndara. Pasi memoria që i jepet një pune duhet të jetë e pandarë,
kjo memorie e shpërndarë kështu nuk mund të përdoret. Një zgjidhje e këtij problemi është
kompaktëzimi i përmendur më parë, që blloqet e ndara memorike i bashkon në një bllok të
pandarë. Faqëzimi (ang. paging) mundëson që memoria e programit të jetë e shpërndarë, duke i
mundësuar vendosjen në çdo pjesë të memories që është e lirë.
5.6.1 Hardveri
Përkrahja hardverike softverit për faqëzim është e dhënë në figurën 5.20. Çdo adresë e
gjeneruar nga procesori është e ndarë në dy pjesë: numrin e faqes (ang. page number) (p) dhe
zhvendosjen në faqe (ang. page offset) (d). Numri i faqes shërben si indeks në tabelën e faqeve.
Tabela e faqeve përmban adresën e bazës së secilës faqe në memorien fizike. Kjo adresë e bazës
kombinohet me zhvendosjene në faqe për të përcaktuar adesën fizike memorike që dërgohet në
njësinë memorike.
100
Fig.5.20 Hardveri për faqëzim
Modeli i memories së faqëzuar është treguar në figurën 5.21. Memoria fizike është e
ndarë në blloqe të madhësisë fikse të quajtur korniza (ang. frame). Memoria logjike është e ndarë
poashtu në blloqe të madhësisë së njejtë të quajtur faqe (ang. page). Kur programi duhet të
ekzekutohet faqet e tij sjellen në cilatdo korniza që janë të lira, ndërsa përmbajtja e tabelës së
faqeve ndërrohet për të pasqyruar lidhjen e faqeve dhe kornizave.
Madhësia e faqeve dhe kornizave është e definuar nga hardveri i kompjuterit. Madhësia e
faqes është e rendit 512, 1024, 2048 ose 4096 bajtë ose fjalë. Në përgjithësi nëse madhësia e
faqes është P, atëherë për adresë logjike U, numri i faqes p dhe zhvendosja e faqes fitohet me:
ku div paraqet pjestimin që si rezultat jep pjesën e plotë të operacionit të pjestimit, ndërsa mod
paraqet mbetjen që fitohet kur të pjestohet U me P. Pasi madhësia e faqes merret si
101
Fig.5.21 Modeli i memories së faqëzuar logjike dhe fizike
eksponent i 2-shit, kalimi nga adresa logjike në numër të faqes dhe zhvendosje është i thjeshtë.
Nëse faqja është e madhësisë 2n njësi adresore (fjalë ose bajtë), atëherë n bitët e rendit më të ultë
të adresës logjike paraqesin zhvendosjen në faqe, ndërsa bitët mbetës të rendit më të lartë tregojnë
numrin e faqes. Duke zgjedhur vlerat e mësipërme për madhësi të faqes i shmangemi pjestimit.
Do të marrim një shembull të thjeshtë për të ilustruar këtë që u tha (Fig.5.22). Ta zëmë se
kemi memorien e kapacitetit 32 fjalë. Madhësia e faqes është 4 fjalë. Adresa logjike 0 paraqet
faqen 0 dhe zhvendosjen 0. Duke shikuar tabelën e faqeve do të shohim se faqja 0 është në
kornizën 5. Në këtë mënyrë adresa logjike 0 pasqyrohet në adresën fizike 20 (=5*4+0). Adresa
logjike 3 (faqja 0, zhvendosja 3) pasqyrohet në adresën fizike 23(=5*4+3). Adresa logjike 4 është
në faqen 1, zhvendosjen 0; bazuar në tabelën e faqeve faqja 1 është e pasqyruar në kornizën 6.
Nga kjo kemi se adresa logjike 4 pasqyrohet në adresën fizike 24 (=6*4+0). Adresa logjike 13
pasqyrohet në adresën fizike 9, e kështu me rradhë.
Faqëzimi paraqet vetvetiu një formë të relokacionit dinamik. Çdo adresë logjike mapohet
në adresë fizike me ndihmën e hardverit për faqëzim.
102
Fig.5.22 Shembulli i memories 32 fjalëshe me faqe 4 fjalëshe
103
Fig.5.23 Kornizat e lira (a) para dhe (b) pas
e fundit e dhënë programit nuk do të jetë plotësisht e shfrytëzuar. Nëse p.sh. madhësia e
programit është 4096 fjalë në sistemin me madhësi të faqes 512 fjalë, programit do ti jepen 8
korniza; nuk do të kemi fragmentim të brendshëm, për arsye se nmadhësia e programit është
shumëfish i madhësisë së faqes (4096=512*8). Nëse programi është i madhësisë 8629 fjalë, atij
do ti nevojiten 16 faqe dhe 437 fjalë. Sistemi do t'ia ndajë 17 korniza. Korniza e fundit nuk do të
104
jetë e shfrytëzuar tërësisht. Fragmentimi intern do të jetë 512-437=75 fjalë. Në rastin më të keq
programi do të kërkojë n faqe dhe 1 fjalë. Në atë rast sistemi do t'ia jep n+1 korniza, duke
shkaktuar fragmentim intern prej gati një kornize. Nëse madhësia e punës nuk është funksion i
madhësisë së faqes mund të presim që mesatarisht për çdo punë të kemi fragmentim intern sa
gjysma e kornizës. Kjo na bie në konkludim se faqet më të vogla janë më të dëshirueshme në këtë
aspekt.
Çdo punë e ka tabelën e vet të faqeve, që së bashku me të dhënat tjera është e vendosur
në bllokun kontrollues të punës (procesit). Kur dispeçerit ti urdhërohet ta startoj një punë, ai
duhet ti mbush regjistrat dhe të definojë vlerat korekte në tabelën hardverike të faqeve nga tabela
e ruajtur e faqeve që i takon shfrytëzuesit.
105
memories. Krejt operacioni mund të jetë vetëm 10% më i ngadalshëm se qasja normale memories.
Nëse numri i faqes nuk gjindet në memorien asociative, duhet ti referohemi tabelës së
faqeve. Kur ta fitojmë numrin e kornizës, mund ta përdorim për qasje memories. Numri i faqes
dhe i kornizës së kërkuar, i gjetur në këtë mënyrë, do të vendoset në regjistra asociativ për të
mundësuar gjetjen e shpejtë për qasjen e ardhshme të njejtës adresë.
Përqindja e të qëlluarit (gjetjes së përmbajtjes së kërkuar, ang. hit rate) varet nga numri i
regjistrave asociativ. Me 8 ose 16 regjistra mund të arrihet të qëlluarit në shkallë 80 deri 90%. Të
qëlluarit 80% do të thotë se në 80% të rasteve kur e kemi kërkuar e kemi gjetë numrin e
dëshiruar të faqes në regjistra asociativ. Nëse kërkimi i regjistarve asociativ zgjatë 50 ns, ndërsa
qasja memories 750ns, atëherë qasja e mapuar memories zgjatë 800ns, në rastin kur numri i faqes
është në regjistra asociativ. Nëse nuk e gjejmë numrin e faqes (50ns), atëherë na nevojitet një
qasje memories (750ns) për të gjetë numrin e kornizës dhe një tjetër (750ns) për t'iu qasë lokaci
onit të dëshiruar memorik, që jep 1550ns. Për të gjetë kohën efektive të qasjes duhet marrë çdo
kohë sipas gjasës së paraqitjes:
koha efektive e qasjes = 0.80*800ns + 0.20*1550ns = 950ns
Ngadalsimi i memories është 26.6% (nga 750ns në 950ns).
Për përqindje të qëlluarit 90% do të kemi:
koha efektive e qasjes = 0.90*800ns + 0.10*1550ns = 875ns
Ngadalsimi i memories është 16.6% (nga 750ns në 875ns).
106
Fig.5.24 Shfrytëzimi i përbashkët i kodit në rrethinën e faqëzuar
Në memorien fizike do të ruhet vetëm një kopje e editorit. Tabela e faqeve e secilit
shfrytëzues do të pasqyrohet në të njetën kopje fizike të editorit, por faqet e të dhënave pasqyro
hen në korniza të ndryshme. Për të përkrahur 40 shfrytëzues që përdorin të njejtin editor, do të na
duhet një kopje e editorit në memorie (40K) dhe 40*5K hapësirë për të dhëna për shfrytëzues.
Madhësia e hapësirës së zënë do të jetë 230K, që paraqet kursim të konsiderueshëm.
Edhe programet tjera mund të përdoren në këtë mënyrë. Të tillë janë kompajlerët,
sistemet për udhëheqjen e bazave të të dhënave, etj. Që kodi të mund të shfrytëzohet nga më
shumë vet njëkohësisht duhet të jetë rihyrës (jo-vetë-modifikues). Ky termin do të thotë se në kod
nuk do të tentohet asnjëherë të ruhet diçka; ai është kod vetëm për lexim (ang. read-only). Faqet
e përbashkëta duhet të jenë të pandryshueshme. Nëse një shfrytëzues do të ndërronte diçka,
ndërrimi do të prekte të gjithë shfrytëzuesit. Natyra read-only e kodit të përbashkët nuk bën ti
lëhet në mëshirë korrektësisë së programeve. Është detyrë e sistemit operativ që këtë ta sigurojë.
5.6.5 Mbrojtja
107
mund të realizohet ashtu që të ofrojë mbrojtje që lejon vetëm leximin, leximin dhe shkruarjen dhe
vetëm ekzekutimin. Duke siguruar bita mbrojtës për secilin lloj të qasjes, mund të lejohet cilido
kombinim i qasjeve të ndryshme. Tentimi i qasjes së palejuar do të shkaktojë ndërprerje.
Zakonisht çdo elementit nga tabela e faqeve i bashkangjitet edhe një bit, biti i validitetit
(ang. valid/invalid bit). Arkitektura e kompjuterit definon një vlerë maksimale të adresës që mund
të gjenerohet. Adresa 16 bitëshe lejon si adresë maksimale vlerën 65535, ndërsa adresa 24 bitëshe
mund të jetë maksimalisht 16,777,215. Në shumicën e rasteve punët janë të kufizuar në hapësirë
më të vogël memorike.
Një cilësi shumë e rëndësishme e faqëzimit është ndarja e kjartë mes pamjes së memories
108
që ka shfrytëzuesi dhe memories reale fizike në kompjuter. Shfrytëzuesi ka përshtypjen se në
sistem ndodhet vetëm një program që zë hapësirë të pandërprerë memorike. Në fakt programi i
shfrytëzuesit është i shpërndarë nëpër tërë hapësirën memorike në të cilën ndodhen edhe
programet tjera. Diferenca mes këndvështrimit të shfrytëzuesit dhe memories reale fizike
tejkalohet përmes hardverit për përkthimin e adresave (ang. address translation) ose mapimin. Ky
hardver mapues e bënë përkthimin e adresave logjike në adresa fizike. Ky mapim është i fshehur
nga shfrytëzuesi dhe kontrollohet nga sistemi operativ.
Një rezutat i ndarjes në adresa logjike dhe fizike është se këto dy memorie mund të mos
jenë të njejta. Në sistemin XDS-940 adresat logjike janë 14 bitëshe; adresat fizike 16 bitëshe.
Numri 3 bitësh i faqes na shërben si indeks për gjetjen e numrit 5 bitësh të kornizës. Kjo do të
thotë se në sistem mund të ketë 4 herë më shumë memorie fizike se sa mund të adresojë një
shfrytëzues. Në këtë sistem multiprogramimi është i thjeshtë; së paku 4 shfrytëzues mund të
gjenden njëkohësisht në memorie.
Kjo qasje është përdorë në fillim te disa minikompjuterë te të cilët adresat logjike 15 ose
16 bitëshe mapoheshin në adresa fizike 17 ose 18 bitëshe. Kjo ka mundësuar praninë e më shumë
shfrytëzuesve njëkohësisht në memorie. Duhet cekur këtu se memoria në dispozicion një
shfrytëzuesi nuk është rritur, për arsye se nuk është rritur edhe hapësira adresore logjike.
Mapimin e kontrollon sistemi operativ dhe ai mund ta aktivizojë për shfrytëzues dhe ta
deaktivizojë për vehte. Pasi sistemi operativ udhëheq memorien fizike ai duhet të dijë gjendjen e
kësaj memorie, duhet të dijë në sa korniza është e ndarë memoria, sa korniza janë të lira, sa janë
të zëna etj. Këto të dhëna ruhen në tabelën e kornizave (ang. frame table). Tabela e kornizave ka
nga një hyrje për çdo kornizë që tregon a është kornizë e lirë apo nëse është e zënë, cila faqe e
cilit proces është e mapuar në të.
5.7 Segmentimi
109
Fig.5.26 Këndvështrimi i shfrytëzuesit i memories
110
programit hyrës. Një kompajlerë mund të krijojë segmentin për variabla globale, segmentin për
stekun e thirrjeve të procedurave për ruajtjen e parametrave dhe adresave kthyese, segmentin e
kodit të procedurave dhe funksioneve dhe segmentin e variablave lokale të procedurave dhe
funksioneve. Një kompajlerë tjetër mund të krijojë segmentet në bazë të ndonjë skeme tjetër.
Louderi do ti merr të gjitha këto segmente dhe do t'ua bashkangjet numrin gjegjës.
5.7.2 Hardveri
111
Fig.5.27 Hardveri i segmentimit
Si edhe tabela e faqeve edhe tabela e segmenteve mund të vendoset në regjistra ose në
memorie. Tabela e vendosur në regjistra mund të kontrollohet shumë shpejtë. Shtimi i zhvendos
jes vlerës së bazës dhe krahasimi me limitin mund të bëhet njëkohësiht, për të shkurtuar kohën.
Kompjuterët PDP-11/45 e shfrytëzojnë këtë qasje. Ky kompjuterë i ka 8 segment regjistra.
Adresa 16 bitëshe formohet nga numri 3 bitësh i segmentit dhe zhvendosja 13 bitëshe. Rregullimi
i tillë lejon 8 segmente 8K-bajtëshe. Çdo hyrje në tabelën e segmenteve e ka adresën e bazës,
gjatësinë dhe grupin e bitëve për kontroll të qasjes. Ata definojnë segmentit si segment të cilit nuk
i është e lejuar qasja, i lejohet vetëm leximi, ose i lejohet leximi dhe shkruarja.
Kompjuteri Burroughs B5500 lejon ekzistencën e 32 segmenteve të madhësisë më së
shumti 1024 fjalë secili. Numri i segmentit është 5 bitësh, ndërsa zhvendosja në kuadër të tij mund
të jetë 10 bitëshe. Përvoja ka treguar se numri i segmenteve ka qenë shumë i vogël, si edhe
gjatësia e segmentit. Kompjuteri GE 645 me sistemin operativ Multics mundësonte 256K
segmente të madhësisë deri 64K.
Kur kemi kaq shumë segmente atëherë nuk është e realizueshme që tabelën e segmenteve
ta mbajmë në regjistra. Kjo tabelë mbahet në memorie e në vendin ku ndodhet ajo tregon regjistri
i bazës së tabelës së segmenteve (ang. Segment Table Base Register, STBR). Meqë numri i
segmenteve të përdorura nga programi
112
Fig.5.28 Shembull i segmentimit
mund të ndryshojë dukshëm nga njëri në tjetrin program, përdoret treguesi i gjatësisë së tabelës së
segmenteve që ndodhet në regjistrin me të njejtin emër (ang. Segment Table Length Register,
STLR). Kur kemi çiftin (s,d) të adresës logjike së pari e kontrollojmë se a është numri i segmentit
legal (a ekziston segmenti i tillë, a është s < STLR). Numrin e segmentit ia shtojmë përmbajtjes në
STBR për të fituar adresën memorike (STBR + s) të hyrjes në tabelën e segmenteve. Kjo hyrje
lexohet nga memoria e procedura vazhdon si mëtutje: e kontrollojmë zhvendosjen se a është më e
madhe se limiti dhe e llogarisim adresën fizike të fjalës së kërkuar si shumë të bazës së segmentit
dhe zhvendosjes në kuadër të tij.
Si edhe te faqëzimi edhe këtu kemi dy qasje memories për një adresë logjike, që
ngadalson shpejtësinë e kompjuterit për dy herë. Zgjidhje e këtij problemi është përdorimi i
regjistrave asociativ në të cilët do të ruhen elementet nga tabela e segmenteve që janë këkuar të
fundit. Grupi relativisht i vogël i regjistrave asociativ (8 deri 16) mund të zvoglojë vonesën në
qasje memories në vetëm 10 deri 15% të kohës së qasjes, kur qasja nuk është e mapuar.
113
Fig.5.29 Adresimi te PDP-11/45
114
Fig.5.30 Përdorimi i përbashkët i segmenteve në sistemin memorik të segmentuar
5.7.5 Fragmentimi
Planifikuesi i punëve duhet të gjejë memorien e lirë për të gjitha segmentet e programit të
shfrytëzuesit. Situata është e ngjashme si te faqëzimi, me ndryshim se këtu segmentet mund të
jenë të madhësive të ndryshme derisa faqet ishin të gjitha të njejta. Pra, si edhe te MVT, ndarja e
memories është problem i ndarjes dinamike të memories, që zakonisht zgjedhet duke përdorur
115
algoritmet Më-së-miri-që-përgjigjet dhe I-pari-që- përgjigjet.
Segmentimi mund të shkaktojë paraqitjen e fragmentimit të jashtëm. Në këtë rast mund të
presim që më shumë memorie të jetë e lirë, ose mund të përdorim kompaktëzimin që të krijojmë
vrimë më të madhe. Kompaktëzimin mund ta bëjmë kurdoqoftë pasi segmentimi është për nga
natyra algoritëm i relokacionit dinamik. Nëse planifikuesi duhet të presë për shkak të mungesës së
memories, atëherë ai mund të kontrollojë rreshtin e proceseve dhe të vendos në memorie ndonjë
punë që ka prioritet më të ultë por edhe kërkesa më të vogla për memorie.
Sa ndikon fragmentimi i jashtëm në segmentim dhe a do të përmirësonim situatën më mirë
me kompaktëzim apo me ekzekutim të punëve më të vogla të prioritetit më të ultë, varet në masë
të madhe nga madhësia e segmentit. Mund të definojmë secilën punë si një segment. Kjo do të na
jep MVT-ën. Rast fundor i kundërt është definimi i secilës fjalë si segment të veçantë. Kjo do të
eliminonte krejtësisht fragmentimin. Nëse madhësia mesatare e segmnetit është e vogël edhe
fragmentimi i jashtëm do të jetë i vogël.
Edhe segmentimi edhe faqëzimi i kanë përparësitë dhe dobësitë. Mund të krijojmë sisteme
të kombinuara që të përfitojmë nga karakteristikat e të dyve. Shembuj tipik janë kompjuterët dhe
sistemet IBM 360/67 dhe GE 645 për Multics.
Në sistemin IBM 360/67 adresa 24 bitëshe ka qenë e ndarë në numrin 12 bitësh të faqes
dhe zhvendosjen 12 bitëshe. Çdo hyrje në tabelën e faqeve është 2 bajtëshe dhe përmban numrin
12 bitësh të kornizës dhe bitin e validitetit. Numri 12 bitësh i faqes mundësontë ekzistencën e
4096 faqeve, që kërkonte 8K bajtë për secilën tabelë të tillë të faqeve. Dëshira ka qenë që adresat
të bëhen 32 bitëshe, e numri i faqes të caktohet me 20 bita. Kjo do të kishte si rezultat tabelën e
faqeve me 1,048,576 hyrje gjegjësisht me madhësi prej 2,097,152 bajtë.
Te hapësira më e madhe adresore pjesa më e madhe e tabelës së faqeve do të ishte e
zbrazët, pasi shumica e programeve e shfrytëzon vetëm një pjesë të hapësirës adresore. Për këtë
arsye tabela e faqeve është segmentuar. Katër bitat e epërm të numrit të faqes janë konsideruar si
numër i segmentit, që është përdorur për zgjedhjen e njërit nga 16 segmentet e tabelës së
segmenteve. Secili segment mund të jetë i gjatë deri 268,435,456 bajtë, edhepse madhësia e tij
duhet të jetë shumëfish i 4096 bajtëve. Hyrja në tabelën e segmenteve tregon në bazën e tabelës
së faqeve për këtë segment dhe gjatësinë e tabelës së faqeve. Në këtë mënyrë pjesë të mëdha të
tabelës së faqeve që përmbanin zero, mund të zvoglohen duke vendosur adresën e tabelës së
faqeve të barabartë me zero.
116
Fig.5.31 Faqëzimi i segmentuar në IBM 360/67
Kjo skemë tani kërkon, në rastin më të keq, tri qasje memories. Grupi prej 8 regjistrave
asociativ e redukon kohën shtesë në vetëm 150ns duke dhënë kohën 750+150=900ns për rastin
kur e dhëna e kërkuar ndodhet në regjistra asociativ.
Me rëndësi është këtu se shfrytëzuesi ka ende para vetës hapësirë lineare të faqëzuar.
Sistemi Multics është gjetë para problemit tjetër. Adresat logjike kanë qenë të formuara
nga numri 18 bitësh i segmentit dhe numri 16 bitësh i zhvendosjes. Edhepse kjo skemë krijon
hapësirë adresore 34 bitëshe, madhësia e tabelave është e tolerueshme pasi numri i ndryshueshëm
i segmenteve implikon regjistrin e gjatësisë së tabelës së segmenteve. Na nevojiten aq hyrje në
tabelën e segmenteve sa kemi segmente. Nuk na paraqiten hyrje të zbrazëta në tabelën e
segmenteve.
Mirëpo me segmente 64K fjalëshe madhësia mesatare e segmentit mund të jetë mjaft e
madhe që do të shkaktojë fragmentim ekstern të madh. Edhe nëse fragmentimi nuk do të
paraqeste problem, koha e kërkimit për dhënjen e segmentit, duke përdorur algoritmin I-pari-që-
përgjigjet ose Më-së-miri-që-përgjigjet, mund të jetë e gjatë. Pra, mund të humbim memorien për
117
arsye të fragmentimit ekstern ose mund të humbim kohë për shkak të kërkimeve të gjata. Ose
edhe njërën edhe tjetrën.
Zgjedhja që u përdor ishte faqëzimi i segmenteve. Faqëzimi eliminon fragmentimin dhe e
bën problemin e vendosjes trivial. Cilado kornizë e lirë mund të përdoret për vendosjen e faqes.
Rezultati është dhënë në Fig.5.32. Dallimi mes kësaj zgjidhjeje dhe segmentimit të pastër qëndron
në atë se hyrja në tabelën e segmenteve nuk përmban adresën e bazës së segmentit, por adresën e
bazës së tabelës së faqeve për këtë segment. Zhvendsoja e segmentit pastaj do të ndahet në
numrin 6 bitësh të faqes dhe zhvendsojen 10 bitëshe të faqes. Numri i faqes shërben që nga tabela
e faqeve të gjindet numri i kornizës. Më në fund numri i kornizës do të kombinohet me
zhvendosjen e faqes për të dhënë adresën e vërtetë fizike.
Tani, për çdo segment duhet të kemi tabelën e veçantë të faqeve. Mirëpo, pasi secili
segment e ka madhësinë e kufizuar nga vlera në hyjen e tij në tabelën e segmenteve, tabela e
faqeve nuk duhet të jetë e madhësisë së plotë. Do të na duhen aq hyrje sa me të vërtetë kërkohen.
Faqja e fundit e secilit segment, në rastin e përgjithshëm, nuk do të jetë e plotë. Kjo do të thotë se
do të kemi gjysmë faqe të fragmentimit intern për segment. Eliminimi i fragmentimit ekstern ka
shkaktuar paraqitjen e fragmentimit intern dhe rritjen e madhësisë së tabelës së faqeve.
Edhe sistemet tjera poashtu e përdorin segmentimin e faqëzuar me kombinime të
ndryshme të madhësisë së segmetit, faqes dhe zhvendosjes.
Skema e treguar më lartë e sistemit operativ Multics që trajton këtë mënyrë të udhëheqjes
së memories është e thjeshtuar. Por, nuk do ta komplikojmë më shumë sqarimin e dhënë.
118
Fig.5.32 Segmentimi i faqëzuar
119
6 Memoria virtuale
120
7. Proceset konkurente
a:=x+y;
b:=z+1;
c:=a-b;
w:=c+1;
7.1.1 Definicioni
Grafi i përparësisë është graf aciklik i orientuar, nyjet e të cilit i përgjigjen instruksioneve
indivuduale. Dega prej nyjes Si deri te nyja Sj do të thotë se instruksioni Sj mund të ekzekutohet
vetëm pasi që instruksioni Si ta kryej ekzekutimin.
Në grafin e përparësisë të dhënë në Fig.7.1 ekzistojnë këto relacione të përparësisë:
- S2 dhe S3 mund të ekzekutohen vetëm pasi të jetë kryer ekzekutimi i S1.
- S4 mund të ekzekutohet pasi të kryhet S2.
- S3 dhe S6 mund të ekzekutohen pasi të kryhet S4.
- S7 mund të ekzekutohet vetëm pasi të kryhen S5, S6 dhe S3.
Të cekim se S3 mund të ekzekutohet njëkohësisht kur edhe S2, S4, S5 dhe S6.
Grafi i përpraësisë duhet të jetë aciklik. Grafi në figurën 7.2 ka këto kufizime: S3 mund të
ekzekutohet vetëm pasi të kryhet S2, ndërsa S2 mund të ekzekutohet vetëm pasi të jetë kryer S3.
Shihet se këto kufizime nuk mund të kënaqen në të njejtën kohë.
121
Fig.7.1 Grafi i përparësisë
122
pjesë të gjitha variablat, vlerave të të cilave do tu referohemi gjatë ekzekutimit të instruksionit Si.
- W(Si) = {b1, b2, ...,bn}, do të jetë bashkësia e shkruarjes (ang. write set), në të cilën
bëjnë pjesë të gjitha variablat vlerat e të cilave do të ndërrohen (shkruhen) me ekzekutimin e
instruksionit Si.
Për të ilustruar këtë mënyrë të shënimit të marrim parasysh instruksionin c:=a-b. Vlerat e
variablave a dhe b do të përdoren për llogaritjen e vlerës së re për c. Pra, a dhe b janë në
bashkësinë e leximit. Vlera e c-ës nuk është përdorë në instruksion, por vlera e saj e re është
definuar me rezultatin e ekzekutimit të instruksionit. Rrjedhimisht c-ja ndodhet në bashkësinë e
shkruarjes e jo në bashkësinë e leximit.
R(c:=a-b) = {a,b}
W(c:=a-b) = {c}
R(w:=c+1) = {c}
W(w:=c+1) = {w}
Prerja e bashkësive R(Si) dhe W(Si) nuk është e thënë të jetë bashkësi e zbrazët. Për shembull në
instruksionin x:=x+2, R(x:=x+2) = W(x:=x+2) = {x}.
Që dy instruksione të njëpasnjëshme të ekzekutohen në mënyrë konkurente dhe përsëri të
japin të njejtin rezultat, duhet të plotësohen këto tri kushte, të njohura si kushtet e Bernsteinit:
1. R(S1) ∩ W(S2) = { }.
2. W(S1) ∩ R(S2) = { }.
3. W(S1) ∩ W(S2) = { }.
Si ilustrim, të marrim S1: a:=x+y dhe S2: b:=z+1. Këto dy instruksione mund të ekzekutohen
njëkohësisht për arsye se:
R(S1) = {x,y}
R(S2) = {z}
W(S1) = {a}
W(S2) = {b}
Instruksioni S2 nuk mund të ekzekutohet konkurent me S3: c:=a-b për arsye se:
7.2 Specifikacionet
123
7.2.1 Konstruksionet fork dhe join
Instruksionet fork dhe join janë dhënë të parën herë nga Conway [1963] dhe nga Dennis
dhe Van Horn [1966]. Ato paraqitnin disa nga elementet e para të gjuhëve programore që specif
ikonin konkurencën.
Instruksioni fork L krijon dy ekzekutime konkurente në program. Një ekzekutim fillon
nga instruksioni i treguar me L, ndërsa tjetri është vazhdim i ekzekutimit nga instruksioni që
pason instruksionin fork.
Që të ilustrojmë këtë do të shqyrtojmë segmentin e ardhshëm programor.
S1;
fork L;
S2;
.
.
.
L: S3;
Pjesa e grafit të përparësisë që i përgjigjet këtij programi është dhënë në Fig.7.3. Kur të
ekzekutohet instruksioni fork L, startohet llogaritja e re nga S3. Kjo llogaritje e re ekzekutohet
konkurent me llogaritjen e vjetër, që vazhdon nga S2.
Instruksioni fork e ndan një llogaritje të vetme në dy llogaritje të pavarura. Prej kësaj e ka
burimin emri i instruksionit, fjala angleze fork do të thotë tërfurk.
Instruksioni join (ang. join, shq. bashko) është instruksion që siguron ribashkimin e dy
llogaritjeve konkurente në një llogaritje. Secila llogaritje duhet të kërkojë që të bashkohet me
tjetrën. Pasi llogaritjet mund të ekzekutohen me shpejtësi të ndryshme, mund të ndodhë që njëra
të kërkojë bashkimin (duke ekzekutuar instruksioni join para tjetrës. Në këtë rast llogaritja që e
ka kërkuar e para bashkimin do të përfundojë ndërsa tjetrës do ti lejohet të vazhdojë. Nëse do të
kishim tri lloga-ritje, dy të parat do të përfundoheshin, ndërsa të tretës do ti lejohej të vazhdojë.
Duhet të dijmë numrin e llogaritjeve në mënyrë që të dijmë ti përfundojmë të gjitha,
përveç të fundit. Instruksioni join përmban parametrin që tregon numrin e llogaritjeve që bashko
124
hen. Kështu ekzekutimi i instruksionit join me parametrin count (shq. numruesi) ka këtë efekt:
count := count-1;
if count <> 0 then quit;
ku count paraqet variabël jonegative të tipit integer, ndërsa quit është instruksion, që përfundon
ekzekutimin. Për dy llogaritje variabla count do të inicializohej në 2.
Instruksioni join duhet të ekzekutohet atomikisht, që do të thotë se ekzekutimi konkurent
i dy instruksioneve join është ekuivalent me ekzekutimin serik të këtyre dy instruksioneve me një
renditje të padefinuar.
Për të ilustruar këtë koncept, të marrim parasysh këtë segment programor:
count:=2;
fork L1;
.
.
.
S1;
go to L2;
L1: S2;
L2: join count;
Pjesa e grafit të përparësisë që i përgjigjet këtij programi është treguar në figurën 7.4.
125
c:=a-b;
w:=c+1;
Ti kthehemi tani grafit të përparësisë nga figura 7.1. Programi gjegjës që përdorë instruksionet
fork dhe join është:
S1;
count:=3;
fork L1;
S2;
S4;
fork L2;
S5;
go to L3
L2: S6;
go to L3;
L1: S3;
L3: join count;
S7;
Nga figura 7.1 shihet se ekziston vetëm një nyje join, S7, në të cilën bashkohen tri
llogaritje. Për këtë arsye vetëm një instruksion join edhe nevojitet. counter për këtë join është i
inicializuar në 3.
Si shembull të fundit të marrim programin që kopjon nga datoteka sekuenciale f në
datotekën tjetër g. Me shfrytëzimin e baferimit të dyfisht (ang. double-buffering) me r dhe s, ky
program mundëson leximin (nga f) konkurent me shkruarjen (në g).
var f, g: file of T;
r,s: T;
count: integer;
begin
reset(f);
read(f,r);
while not eof()
do begin
count:=2
s:=r;
fork L1;
write(g,s);
go to L2;
L1: read(f,r);
L2: join count;
end;
write(g,r);
end
Instruksionet fork dhe join janë mjete të fuqishme për shkruarjen e programeve
konkurente. Mirëpo, programet që shfrytëzojnë këto instruksione kanë strukturë të
126
padëshirueshme. Instruksioni fork është për nga efekti i ngjashëm me instruksionin go to në
pikën e ekzekutimit. go to është urdhër i padëshirueshëm në çdo program dhe duhet tentuar që
gjithsesi të eliminohet ose së paku të shfrytëzohet sa më pak.
Çdo Si është instruksion i veçantë. Të gjitha instruksionet që ndodhen mes parbegin dhe parend
mund të ekzekutohen në mënyrë konkurente. Grafi i përparësisë që i përgjigjet instruksionit të
mësipërm është dhënë në Fig.7.5, ku S0 dhe Sn+1 janë instruksione që paraqiten para dhe pas
instruksionit parbegin/parend respektivisht. Instruksioni Sn+1 mund të ekzekutohet vetëm pasi të
kenë përfunduar të gjitha Si-të, i=1,2,...,n.
Ta ilustrojmë këtë koncept me disa shembuj. Të marrim përsëri programin e parë. Për të
lejuar ekzekutimin konkurent të dy instruksioneve të para programi mund të shkruhet me
ndihmën e konstruksionit parbegin/parend si:
parbegin
a:=x+y;
b:=z+1;
parend;
c:=a-b;
w:=c+1;
S1;
127
parbegin
S3;
begin
S2;
S4;
parbegin
S5;
S6;
parend;
end;
parend;
S7;
var f, g: file of T;
r, s: T;
begin
reset(f);
read(f,r);
while not eof()
do begin
s:=r;
parbegin
write(g,s);
read(f,r);
parend;
end;
write(g,r)
end.
Instruksioni konkurent mund të shtohet lehtë në gjuhët e bllok strukturuara moderne të nivelit të
lartë dhe tregon shumë përparësi që i kanë edhe instruksionet tjera të strukturuara kontrolluese.
7.2.3 Krahasimi
S1;
128
count1:=2;
S2;
S4;
count2:=2;
fork L2;
S5;
go to L3;
L1: S3;
L2: join count1;
S6;
L3: join count2;
S7;
Edhepse instruksioni konkurent vetëm nuk mund ti zgjidhë të gjitha problemet e dhëna
me grafe të përparësisë, shtimi i mekanizmave tjerë instruksionit konkurent i mundëson të barazo
het për nga fuqia me grafet e përparësisë. Kjo është aq më tepër e mundshme, pasiqë nuk do të
presim që të gjitha grafet e përparësisë të kanë nevojë të implementohen, por vetëm ato që kanë
të bëjnë me probleme të botës reale.
129
Në pjesët paraprake treguam grafet e përparësisë dhe mënyrën se si konkurenca mund të
prezentohet në një program. Tani do të formalizojmë kuptimin e ekzekutimit konkurent duke e
prezentuar përsëri konceptin e procesit sekuencial.
Joformalisht proces sekuencial është programi që ekzekutohet. Do të potencojmë edhe
një herë se programi vetvetiu nuk është proces; programi është entitet pasiv, ndërsa procesi është
entitet aktiv. Ekzekutimi i procesit duhet të përparojë në mënyrë sekuenciale (prej kësaj edhe
rrjedh emri proces sekuencial). Kjo do të thotë se në cilindo moment kohor ekzekutohet më së
shumti një instruksion i procesit. Pra, edhepse dy procese mund të jenë të lidhura për një
program, ato përsëri konsiderohen si dy sekuenca të veçanta ekzekutive.
Deri tash kemi pa se llogaritjet konkurente brenda një programi mund të modelohen me
grafet e përparësisë. Kemi treguar poashtu dy shënime të ndryshme (fork/join dhe
parbegin/parend) për të përshkruar llogaritjen konkurente. Pasi dëshirojmë që llogaritjen e tillë
ta përshkruajmë si bashkësi të proceseve sekuenciale, duhet të krijojmë lidhjen mes këtyre dy
koncepteve: proceseve dhe grafeve të përparësisë.
Është e përshtatshme që secilën nyje të grafit të përparësisë ta shikojmë si proces
sekuencial. Në rrethinë të tillë proceset paraqiten dhe zhduken në mënyrë dinamike gjatë kohës së
një ekzekekutimi të programit. Kjo skemë mund të na shkaktojë punë shtesë (ang. overhead) në
130
pikëpamje të numrit të proceseve që duhet krijuar dhe shkatërruar. Kjo punë shtesë mund të
minimizohet nëse i bashkojmë në një proces të vetëm ato aktivitete që mund të kryhen
sekuencialisht. Ky ndërrim duhet bërë me kujdes ashtu që mos të zvoglohet niveli i konkurencës
që është i lejuar në llogaritje. Për shembull në grafin e përparësisë nga figura 7.1 instruksionet S2
dhe S4 mund të bashkohen në një proces të vetëm.
Në vazhdim do të përshkruajmë formalisht efektin në procese sekuenciale të instruksionit
konkurent të Dijkstras dhe instruksioneve fork/join. Për të thjeshtuar diskutimin, do të marrim
vetëm konstruksionin fork/join. Instruksionin konkurent mund ta simulojmë gjithmonë me
konstruksionin fork/join. Le të jetë:
count:=n;
fork L2;
fork L3;
.
.
fork Ln;
S1;
go to Lj;
L2: S2;
go to Lj;
L3: S3;
go to Lj;
.
.
Ln: Sn;
Lj: join count;
Kur procesi Pi e ekzekuton instruksionin fork L, krijohet procesi ri Pj. Pi dhe Pj e ndajnë
të njejtin program, si dhe çfarëdo që të jenë variabla globale. (Duhet të na jetë e qartë se në
rrethinë të tillë programet duhet shkruar si kod rihyrës). Dallimi kryesor mes proceseve Pi dhe Pj
është se numruesi i instruksioneve i procesit Pj ka vlerën L dhe se regjistrat e tij intern hardverik
janë të inicializuar në pajtim me këtë.
Kur të hasim në instruksionin join count vlera e count zvoglohet për një. Nëse rezultati
është i barabartë me zero, procesi do ta vazhdoje ekzekutimin. Përndryshe procesi do të
përfundojë.
131
Fig.7.8 Grafi i procesit
Grafi i procesit është pemë e orientuar që ka rrënjën, ndërsa nyjet e pemës i përgjigjen
proceseve. Dega prej nyjes Pi te Pj tregon se procesi Pi e ka krijuar procesin Pj. Në këtë rast do të
themi se Pi është prind i Pj, ndërsa Pj është fëmij i Pi. Grafi duhet ta ketë rrënjën pasi çdo proces
mund ta ketë më së shumti një prind, por mund të ketë aq fëmij sa ti krijon (figura 7.8).
Diferenca ndërmjet grafit të procesit dhe grafit të përparësisë është në ate se grafi i
procesit tregon raportin e krijimit, ndërsa grafi i përparësisë raportin e përparësisë. Në grafin e
procesit dega prej Pi te Pj nuk implikon se Pj mund të ekzekutohet pas Pi, por vetëm tregon se Pi
e ka krijuar Pj; Pi dhe Pj mund të ekzekutohen në mënyrë konkurente.
Do të diskutojmë formimin e raportit prind/fëmij dhe dallimet kryesore mes procesit prind
dhe fëmij.
Krijimi i procesit
Kur një proces e krijon një proces të ri, me ndonjë operacion të krijimit (p.sh. fork),
ekzistojnë disa implementime të ndryshme, që dallohen në lidhje me këto qështje:
1. Ekzekutimi. Konkurent ndaj atij sekuencial.
a. Prindi vazhdon të ekzekutohet në mënyrë konkurente me fëmijtë e tij.
b. Prindi pret derisa të gjithë fëmijtë e tij të përfundojnë.
2. Shfrytëzimi i përbashkët (ang. sharing). Të gjithë ndaj disave.
a. Prindi dhe fëmijët shfrytëzojnë bashkarisht të gjitha variablat.
b. Fëmijët shfrytëzojnë vetëm një nënbashkësi të variablave të prindit.
Të themi diçka për secilin nga këto opcione.
Opcioni 1a është marrë në konstruksionin fork/join. Kur procesi Pi ta ekzekuton
instruksionin fork L, krijohet procesi i ri Pj, ku Pi është prindi i Pj. Të dy proceset vazhdojnë të
ekzekutohen në mënyrë konkurente.
Opcioni 1b është pranuar nga instruksioni konkurent. Kur procesi Pi ta ekzekuton
instruksionin
132
krijon procese të reja që ekzekutohenn në konkurencë. Procesi Pi do të pret derisa të gjitha këto
procese të kryhen. Pas kësaj procesi Pi do të vazhdojë ekzekutimin nga instruksioni që pason
instruksionin konkurent.
Opcioni 2a është pranuar në të dy konstruksionet e përmendura. Edhe te fork/join edhe
te instruksioni konkurent prindi dhe fëmijtë shfrytëzojnë së bashku të gjitha variablat.
Opcioni 2b është pranuar në sistemin operativ UNIX. Kur procesi Pi e krijon një proces të
ri Pj, ky proces i ri e ka imazhin e ri të pavaruar memorik të Pi-së, duke përfshirë këtu edhe lejen e
qasjes të gjitha datotekave të hapura të Pi-së. Mirëpo, variablat të cilave mund tu qaset Pi, nuk
mund tu qaset Pj pasi Pi dhe Pj kanë imazhe të pavarura memorike. Pra, në UNIX Pi dhe Pj mund
të komunikojnë vetëm përmes datotekave të përbashkëta.
Në përgjithësi, një proces do të ketë nevojë për resurse të caktuara (koha e procesorit,
memoria, datotekat, njësitë hyrëse-dalëse) me qëllim të kryerjes së detyrës së dhënë. Kur procesi
e krijon një nënproces, nënprocesi mund të jetë në gjendja të kërkojë resurset direkt nga sistemi
operativ ose mund të jetë i kufizuar në nënbashkësinë e resurseve të prindit. Prindi do të duhet
ndoshta t'ua ndajë resurset e veta fëmijve ose do të jetë në gjendje që disa resurse (memorien ose
datotekat) ti shfrytëzojë së bashku me disa prej fëmijëve të vet. Duke e kufizuar procesin fëmij në
shfrytëzimin e vetëm një nënbashkësie të resurseve të prindit, e parandalojmë procesin që ta
tejngarkojë sistemin me krijimin e shumë nënproceseve.
Përfundimi i procesit
kill id;
ku id është emri i procesit që do të përfundojë. Operacioni kill (shq. vraje, mbyte) zakonisht
mund të thirret vetëm nga procesi që e ka krijuar procesin që duam ta përfundojmë. Mund të
vërejmë se procesi duhet të dijë identitetin e fëmijve të tij. Pra kur një proces e krijon një proces
të ri, identiteti i procesit të krijuar do ti bëhet i njohur procesit prind. Për shembull,
id:=fork L
133
Procesi që nuk përfundon derisa sistemi operativ është aktiv quhet statik; procesi që
mund të përfundojë quhet dinamik. Nëse sistemi përbëhet vetëm nga numër i kufizuar i
proceseve statike, atëherë edhe grafi gjegjës i proceseve është poashtu statik; d.m.th. nuk ndërron
asnjëherë. Duhet të kemi kujdes me terminet e përdorura, për arsye se në fillim grafi i proceseve
nuk e ka asnjë nyje. Që të evitojmë çdo dyshim do të themi se graf statik i proceseve është grafi
që gjendjen e vet statike e mbërrin pas një kohe të shkurtë fillestare.
Diferenca mes këtyre dy skemave është në shumë pikëpamje e ngjashme me diferencën në
mes të gjuhëve të bllok strukturuara programore dhe gjuhëve që përdorin ndarjen statike të
memories. Në të parat, blloqet, gjegjësisht proceset, paraqiten dhe zhduken dinamikisht, ndërsa
në te dytat blloqet, gjegjësisht proceset, fiksohen në momentin e deklarimit. Skema dinamike
është më fleksibile, por kërkon më shumë punë shtesë, për shkak të krijimit dhe shkatërrimit të
proceseve.
Modeli i krijuar deri tani paraqet sistemin që përbëhet nga një numër i proceseve
kooperuese sekuenciale, që ekzekutohen në mënyrë asinkrone dhe shfrytëzojnë disa të dhëna të
përbashkëta. Do të japim një shembull që është reprezentativ për sistemet operative.
Proceset e llojit prodhuesi/konsumuesi janë të shpeshtë në sistemet operative. Prodhuesi
është proces që prodhon informata që konsumohen nga ana e procesit të konsumuesit. P.sh.
drajveri i printerit prodhon karakterë që konsumohen nga printeri. Kompajleri mund të krijojë
kod simbolik, që mund të konsumohet nga asembleri etj.
Për të lejuar ekzekutimin konkurent të procesit të prodhuesit dhe procesit të konsumuesit,
duhet të krijojmë një bashkësi të baferëve që do të mbushen nga prodhuesi dhe do të zbrazen nga
konsumuesi. Prodhuesi mund të prodhojë për njërin bafer derisa në të njejtën kohë konsumuesi
do të shpenzojë nga baferi tjetër. Prodhuesi dhe konsumuesi duhet të jenë të sinkronizuar,
ashtuqë konsumuesi mos të tentojë të konsumojë prodhime që ende nuk janë krijuar. Në këtë
situatë konsumuesi duhet të presë derisa të prodhohet diçka.
Problemi prodhues/konsumues me numër të pakufizuar të baferëve, nuk imponon
kurrfarë kufizimi në numrin e baferëve. Në këtë rast konsumuesi do të duhet ndonjëherë të presë
për prodhim të ri, por prodhuesi do të mundet gjithnjë të prodhojë diçka; gjithmonë do të
ekzistojnë baferë të zbrazët. Problemi prodhues/konsumues me numër të kufizuar të
baferëve, supozon se ekziston një numër i kufizuar i baferëve, n. Në këtë rast, konsumuesi duhet
të presë nëse të gjithë baferët janë të zbrazët, ndërsa prodhuesi duhet të presë nëse të gjithë
baferët janë të zënë.
Në vazhdim është dhënë zgjidhja e problemit të prodhuesve dhe konsumuesve për numër
të kufizuar të baferëve. Bashkësia e baferëve është implementuar si rresht cirkular (rrethor), me
dy tregues logjik: in (shq. brenda) dhe out (shq. jashtë). Variabla in tregon baferin e ardhshëm të
zbrazët, ndërsa out tregon baferin e parë të plotë. Bashkësia është e zbrazët kur in = out;
bashkësia është e mbushur kur in+1 mod n = out.
Instruksioni skip paraqet instruksionin që nuk bën asgjë. Rreshti while condition do skip,
vetëm e teston konditën secilën herë, deri në momentin kur më nuk vlen.
134
out:=0;
parbegin
producer: begin
repeat
...
prodhoje një element në nextp
...
while in+1 mod n = out do skip;
buffer[in]:=nextp;
in:=in+1 mod n;
until false;
end;
consumer: begin
repeat
while in=out do skip;
nextc:=buffer[out];
out:=out+1 mod n;
...
konsumo një element nga nextc
...
until false;
end;
parend;
Ky algoritëm lejon që më shumti n-1 baferë të jenë të mbushur në të njetën kohë. Nëse do të
tentonim ta eliminojmë këtë mëngësi, do të marrim një variabël integer të quajtur counter (shq.
numruesi) që do ta inicializojmë në 0. counter inkrementohet secilën herë kur një bafer i plotë i
shtohet bashkësisë dhe dekrementohet secilën herë kur një baferë i plotë largohet nga bashkësia.
Kodi për procesin e prodhuesit mund të modifikohet në këtë mënyrë:
repeat
...
prodhoje një element në nextp
...
while counter=n do skip;
buffer[in]:=nextp;
in:=in+1 mod n;
counter:=counter+1;
until false;
repeat
while counter=0 do skip;
nextc:=buffer[out];
out:=out+1 mod n;
counter:=counter-1;
...
135
konsumo një element nga nextc
...
until false;
Edhepse veç e veç edhe rutina e prodhuesit edhe ajo e konsumuesit janë pa gabime, ato mund të
mos funksionojnë si duhet kur të ekzekutohen në mënyrë konkurente. Të supozojmë se vlera e
variablës counter është momentalisht 5 dhe se proceset e prodhuesit dhe konsumuesit e
ekzekutojnë në mënyrë konkurente instruksionin counter:=counter+1; dhe instruksionin counter
:= counter-1. Pas ekzekutimit të këtyre dy instruksioneve vlera e variablës counter mund të jetë 4,
5 ose 6. Rezultati i vetëm i saktë është counter = 5, që do të gjenerohet nëse prodhuesi dhe
konsumuesi ekzekutohen ndamas.
Se vlera e counter nuk është e saktë mund të vërtetojmë në vazhdim. Instruksioni
counter:=counter+1 mund të implementohet në gjuhë të makinës si:
regjistri1 := counter;
regjistri1 := regjistri1 + 1
counter := regjistri1;
regjistri2 := counter;
regjistri2 := regjistri2 - 1
counter := regjistri2;
ku regjistri2 është poashtu regjistër lokal i procesorit. Edhepse regjistri1 edhe regjistri2 mund të
jenë regjistër i njetë fizik (p.sh. akumulator), të përkujtojmë se përmbajtja e regjistrit do të ruhet
dhe restaurohet nga ana e rutinave të planifikimit të procesorit: përpunuesit të ndërprerjeve (ang.
interrupt handler) dhe dispeçerit.
Ekzekutimi konkurent i instruksioneve "counter := counter + 1" dhe "counter := counter
- 1" është ekuivalent me ekzekutimin sekuencial, ku instruksionet e nivelit më të ultë (të nivelit të
makinës) të treguara më lartë janë të ndërlidhura në një renditje arbitrare (por, në renditje që ruan
renditjen e ekzekutimit të instruksioneve të nivelit më të ultë në kuadër të instruksionit të gjuhës
më të lartë). Një ndërlidhje e tillë mund të jetë:
Si po vërehet kemi ardhë deri te gjendja jo e saktë "counter = 4", që na tregon se janë katër
bafera të plotë, kur në fakt janë 5 baferë të plotë. Nëse e ndërrojme renditjen e ekzekutimit për T4
dhe T5 do të arrijmë përsëri te gjendja jokorrekte "counter = 6".
Deri te kjo gjendje kemi mbërri për arsye se i kemi lejuar të dy proceset që të manipulojnë
në mënyrë konkurente me variablën counter. Ekzekutimi konkurent i këtyre dy instruksioneve
është në kundërshtim me kushtet e Bernsteinit. Që të zgjidhim këtë problem duhet të jemi të
sigurt se vetëm nga një proces në një moment kohor mund të manipulojë me variablën counter.
136
Ky observim na bjen te problemi i seksionit kritik.
Të marrim parasysh sistemin e n proceseve {P1, P2, ..., Pn} që bashkëpunojnë mes veti.
Secili proces e ka segmentin e kodit të quajtur seksion kritik (ang. critical section) në të cilin
procesi mund ti lexojë variablat e përbashkëta, azhurojë tabelat, të shkruajë në datotekë, etj.
Cilësi e rëndësishme e sistemit është që derisa një proces është duke u ekzekutuar në seksionin e
tij kritik asnjë proces tjetër nuk bën të ekzekutohet në procesin e vet kritik. Pra ekzekutimi i
seksioneve kritike nga ana e proceseve është reciprokisht i përjashtueshëm në kohë. Problemi i
seksionit kritik paraqet problemin e gjetjes së protokolit që proceset mund ta përdorin për të
bashkëpunuar. Çdo proces duhet të kërkojë lejen për të hyrë në seksionin e vet kritik. Pjesa e
kodit në të cilën është implementuar kjo kërkesë quhet seksioni hyrës (ang. entry section).
Seksioni kritik mund të jetë i pasuar nga seksioni dalës (ang. exit section). Pjesa që mbetë e kodit
quhet seksioni mbetës (ang. remainder section).
Zgjidhja e problemit të përjashtimit reciprok duhet të kënaq këto kushte:
a. Përjashtimi reciprok. Nëse procesi Pi është duke ekzekutuar kodin nga seksioni i tij
kritik, atëherë asnjë proces tjetër nuk bën të ekzekutojë kodin nga seksioni i vet kritik.
b. Përparimi. Nëse asnjë proces nuk është duke u ekzekutuar në seksionin e vet kritik
dhe ekzistojnë disa procese që dëshirojnë të hyjnë në seksionin e tyre kritik, atëherë vetëm
proceset që nuk janë duke u ekzekutuar në seksionin e tyre mbetës mund të marrin pjesë në
vendimin se cilit proces do ti lejohet që i ardhshmi të hyj në seksionin e vet kritik. Kjo zgjedhje
nuk bënë të shtyhet pakufi.
c. Pritja e kufizuar. Numri i hyrjeve në seksionin kritik që do tu lejohen proceseve tjera,
pas momentit kur procesi ka dhënë kërkesën për të hyrë në seksionin e vet kritik, deri në
momentin para se kjo kërkesë ti plotësohet, duhet të jetë i kufizuar.
Supozohet se proceset ekzekutohen me shpejtësi jo-zero. Mirëpo, nuk bën të kemi
kurrfarë supozimesh në lidhje me shpejtësinë relative të proceseve.
Në vazhdim do të japim zgjidhjet për problemin e seksionit kritik që kënaqin tri kushtet e
dhëna më parë. Zgjidhjet e treguara nuk bazohen në kurrfarë parasupozimesh që kanë të bëjnë me
instruksionet hardverike ose numrin e procesorëve që softveri i përkrah. Është supozuar se
instruksionet themelore të gjuhës së makinës, siç janë instruksionet primitive load (shq. mbushe,
ngarkoje), store (shq. ruaje) dhe test, ekzekutohen atomikisht. Do të thotë se, nëse dy instruksi
one të tilla ekzekutohen njëkohësisht, rezultati i tyre do të jetë ekuivalent me rezultatin e ekzeku
timit të tyre sekuencial me ndonjë renditje të panjohur. Pra, nëse load dhe store ekzekutohen në
mënyrë simultane, load do të fitojë ose vlerën e re ose të vjetrën, por kursesi ndonjë kombinim të
tyre.
begin
deklarimi i variablave të përbashkëta
parbegin
137
P0;
P1;
parend;
end.
repeat
seksioni hyrës;
seksioni kritik;
seksioni dalës;
seksioni mbetës;
until false;
Algoritmi 1
repeat
while turn <> i do skip;
seksioni kritik;
turn := j;
seksioni mbetës;
until false;
Kjo zgjidhje na siguron se vetëm një proces në një moment mund të jetë në seksionin e vet kritik.
Mirëpo algoritmi nuk kënaq kushtin e përparimit, pasi kërkon zëvendsimin e përpiktë të
proceseve në ekzekutimin e seksionit kritik. Për shembull, nëse turn = 0 dhe P1 dëshiron të hyjë
në seksionin e tij kritik, nuk do të mund ta bëj këtë edhepse ndoshta P0 ndodhet në seksionin
mbetës.
Algoritmi 2
138
var flag: array [0..1] of boolean;
Elementet e fushës janë të inicializuar në false. nëse flag[i] është true atëherë procesi Pi është
duke u ekzekutuar në seksionin e vet kritik.
Struktura e përgjithshme e procesit Pi do të jetë:
repeat
while flag[j] do skip;
flag[i]:=true;
seksioni kritik;
flag[i]:=false;
seksioni mbetës;
until false;
Në këtë algoritëm së pari e kontrollojmë a është procesi tjetër në seksionin e tij kritik (flag[j] =
true) dhe nëse është do të presim. Pas kësaj e vendosim indikatorin tonë (flag[i] := true) dhe
hyjmë në seksionin tonë kritik. Kur të dalim nga seksioni kritik e resetojmë indikatorin tonë
(flag[i]:=false) për të lejuar procesin tjetër të hyjë në seksionin e tij kritik nëse ka qenë duke
pritur.
Ky algoritëm nuk siguron se vetëm një proces në një moment do të ekzekutohet në
seksionin e tij kritik. Për shembull, të shikojmë sekencën e mundshme:
Tani kemi ardhë në gjendjen ku edhe P0 edhe P1 janë në seksionin kritik, duke shkelur në këtë
mënyrë kërkesën për përjsashtim reciprok.
Ky algoritëm është esencialisht i varur nga koha e ekzekutimit të proceseve. Sekuenca e
treguar mund të derivohej nga rrethina ku disa procesorë janë duke ekzekutuar proceset në
mënyrë konkurente ose ku ndërprerja (siç është ndërprerja e tajmerit) është paraqitë menjëherë
pas ekzekutimit të hapit T0 (dhe përsëri pas hapit T2), e procesori ka kaluar prej njërit në tjetrin
proces.
Algoritmi 3
repeat
flag[i]:=true;
139
while flag[j] do skip;
seksioni kritik;
flag[i]:=false;
seksioni mbetës;
until false;
Pra, në këtë algoritëm së pari e vendosim flag[i]=true, për të sinjalizuar se dëshirojmë të hyjmë në
seksionin tonë kritik. Pastaj, kontrollojmë indikatorin flag[j] për të parë se a dëshiron edhe
procesi tjetër të hyjë në seksionin e tij kritik. Nëse është ashtu, do të presim. Pastaj hyjmë në
seksionin tonë kritik. Me të dalur nga seksioni kritik e vendosim indikatorin tonë në false
(flag[i]=false), për ti lejuar procesit tjetër (nëse është duke pritur) të hyjë në seksionin e tij kritik.
Në këtë zgjidhje, kërkesa për përjashtimin reciprok është kënaq. Fatkeqësisht, kërkesa për
përparim nuk është plotësuar. Për të treguar këtë të marrim sekuencën:
Tani P0 dhe P1, janë duke u sjellur pa ia nda, secili në unazën e vet while.
Algoritmi 4
Në fillim flag[0] = flag[1] = false, ndërsa vlera e turn është e parëndësishme (0 ose 1). Struktura e
procesit Pi është:
repeat
flag[i]:=true;
turn:=j;
while(flag[j] and turn=j) do skip;
seksioni kritik;
flag[i]:=false;
seksioni mbetës;
until false;
140
Për të hyrë në seksionin tonë kritik, më së pari e vendosim indikatorin tonë në true (flag[i]=true),
dhe vërtetojmë se është rradha në procesin tjetër të hyjë në seksionin e vet kritik nëse dëshiron
(turn=j). Nëse të dy proceset provojnë të hyjnë në seksionin e tyre kritik, turn do të merr vlerën
edhe i edhe j në kohë përafërsisht të njejtë. Vetëm njëra prej këtyre vlerave do të qëndrojë më
gjatë, tjetra do të paraqitet, por menjëherë do të ndërrohet. Vlera e turn do të vendosë se cili nga
dy proceset do të hyjë i pari në seksionin kritik.
Të përkujtojmë se për të vërtetuar zgjidhjen e Petersonit na duhet të kemi parasysh se
edhe për të duhet të vlejë (a) përjashtimi reciprok i proceseve, (b) kërkesa për përparim dhe (c)
koha e kufizuar e pritjes.
Për të vërtetuar cilësinë e parë të zgjidhjes, (a), do të cekim se çdo Pi hyn në seksionin e
vet kritik nëse flag[j] = false ose turn = i. Poashtu duhet vërejtur se nëse të dy proceset do të
mund të ekzekutoheshin njëkohësisht në seksionet e tyre kritike atëherë flag[0] = flag[1] = true.
Këto dy observime implikojnë se P0 dhe P1 nuk kanë mundur të ekzekutojnë me sukses
instruksionet e tyre while në përafërsisht kohë të njejtë, pasi vlera e turn mund të jetë ose 0 ose 1,
por jo edhe 0 edhe 1. Prej kësaj rrjedh se njëri prej proceseve, ta marrim Pj, do të duhet ta ketë
kryer me sukses ekzekutimin e instruksionit while, derisa Pi do të duhet ta ekzekutojë edhe së
paku një instruksion shtesë "turn=j". Pasi në këtë moment kohor flag[j]=true dhe turn=i, kushte
që do të vlejnë gjatë gjithë kohës së ekzekutimit të Pj në seksionin e tij kritik konkludojmë se
përjashtimi reciprok është ruajtur.
Për të vërtetuar vetitë (b) dhe (c), të cekim se procesi Pi mund të ndalohet të hyj në
seksionin e tij kritik vetëm nëse ka mbetë në unazën while me kushtet flag[j]=true dhe turn=j; kjo
është e vetmja unazë. Nëse Pj nuk është i interesuar të hyjë në seksionin e vet kritik, atëherë
flag[j]=false, që mundëson Pi të hyjë në seksionin kritik të vetin. Nëse Pj e ka vendosur
flag[j]=true dhe është poashtu duke u ekzekutuar në instruksionin e tij while, atëherë do të jetë
ose turn=i ose turn=j. Nëse turn=i atëherë Pi do të hyjë në seksionin kritik; nëse turn=j, Pj do të
hyjë në seksionin kritik. Me të dalë nga seksioni kritik, Pj do ta resetojë indikatorin e vet
(flag[j]=false), duke i mundësuar procesit Pi që të hyjë në seksionin kritik. Nëse Pj do ta setojë
indikatorin e vet (flag[j]=true), ai duhet poashtu ta vendosë edhe turn=i. Pra, pasi Pi nuk
ndryshon vlerën e variablës turn derisa ekzekuton instruksionin while, Pi do të hyj në seksionin
kritik (përparimi) pas më së shumti një hyrjeje në seksionin kritik të procesit Pj (pritja e kufizuar).
Algoritmi 5
(Emrat e variablave do ti lëmë ta pandryshuara, por për lexuesin që nuk qëndron më së miri me
gjuhën angleze të japim emrat e mundshëm të variablave në gjuhën shqipe: ang. idle shq. i
papunë, ang. want_in shq dëshiron_brenda, ang. in_cs, shq. në_sk. Në princip, emrat e variablave
141
mund ti zgjedhim si të dojmë.)
Në fillim të gjitha elementet e flag kanë vlerën idle, vlera iniciale e variablës turn është e
parëndësishme (mes 0 dhe n-1).
Struktura e procesit Pi është:
var j: 0..n;
repeat
repeat
flag[i]:=want_in;
j:=turn;
while j<>i
do if flag[j] <> idle
then j:=turn;
else j:=j+1 mod n;
flag[i]:=in_cs;
j:=0;
while (j<n) and (j=i or flag[j]<>in_cs) do j:=j+1;
until (j>=n) andw(turn=i or flag[turn]=idle);
turn:=i;
seksioni kritik;
j:=turn+1 mod n;
while (flag[j]=idle) do j:=j+1 mod n;
turn:=j;
flag[i]:=idle;
seksioni mbetës
until false;
Algoritmi 6
142
Qasje tjetër problemit të seksionit kritik ka dhënë Lamporti [1974], që prezentoi një
algoritëm të quajtur algoritmi i furrës. Ky algoritëm është zhvilluar për rrethinë të distribuar. Ne
do të kufizohemi në ato asekte të algoritmit që kanë të bëjnë me rrethinënë e centralizuar.
Algortimi i furrës është i bazuar në mënyrën e shërbimit të myshterijve në furra,
restorante, ëmbëltorë e të ngjashme. Me të hyrë në dyqan, myshterisë i jepet një numër. Myshteria
që ka numrin më të vogël do të shërbehet i ardhshmi. Fatkeqësisht, algoritmi nuk garanton se dy
procese nuk do të fitojnë numrin e njejtë. Në rast se ndodh që dy procese të fitojnë të njejtin
numër do të shëbehet ai që e ka emrin "më të vogël". Kjo do të thotë se nëse Pi dhe Pj e fitojnë të
njejtin numër dhe nëse i<j, atëherë Pi do të shërbehet i pari. Pasi emrat e procese janë unik dhe
plotësisht të renditur, algoritmi është plotësisht deterministik.
Strukturat e përbashkëtat të të dhënave janë:
repeat
choosing[i]:=true;
number[i]:=max(number[0], number[1], ..., number[n-1])+1;
choosing[i]:=false;
for j:=0 to n-1
do begin
while choosing[j] do skip;
while number[j]<>0
and (number[j],j)<number[i],i) do skip;
end;
seksioni kritik;
number[i]:=0
seksioni mbetës;
until false;
143
- number[k] <> 0, dhe
- (number[i],i) < (number[k],k).
Kështu ai vazhdon të sjellet në unazën while deri sa Pi të del nga seksioni kritik.
Që cilësitë e përparimit dhe pritjes së kufizuar të vërtetohen, mjafton të vërejmë se
proceset hyjnë në seksionin e tyre kritik sipas rradhës (i pari që vjen i pari shërbehet).
repeat
while Test_and_set(lock) do skip;
sksioni kritik;
lock:=false;
seksioni mbetës;
144
until false;
Nëse makina përkrah instruksionin Swap, atëherë përjashtimi reciprok mund të sigurohet në
mënyrë të ngjashme. Variabla globale e Boolit lock do të inicializohet në false. Çdo proces e ka
variablën lokale të Boolit key (çelësi).
repeat
key:=true;
repeat
Swap (lock, key);
until key = false;
seksioni kritik;
lock:=false;
seksioni mbetës;
until false;
var j: 0..n-1;
key: boolean;
repeat
waiting[i]:=true;
key:=true;
while waiting[i] and key do key:=Test_and_set(lock);
waiting[i]:=false;
seksioni kritik;
j:=i+1 mod n;
while (j<>i) and (not waiting[j]) do j:=j+1 mod n;
if j=i then lock:=false;
else waiting[j]:=false;
145
seksioni dalës;
until false;
Për të vërtetuar se vlen kërkesa për përjashtimin reciprok, do të cekim se procesi Pi mund
të hyjë në seksionin e tij vetëm nëse waiting[i]=false ose key=false. Key mund të bëhet false
vetëm me ekzekutimin e Test_and_set. Procesi i parë që do të ekzekutojë Test_and_set do të
gjen key=false; të gjithë të tjerët duhet të presin. waiting[i] mund të bëhet false vetëm nëse një
proces tjetër lëshon seksionin e vet kritik; vetëm një waiting[i] ka vlerën true, duke mirëmbajtur
kërkesën për përjashtim reciprok.
Për të vërtetuar kërkesën për përparim, do të cekim se argumentet e parashtruara më lartë
për përjashtimin reciprok vlejnë edhe këtu, pasi procesi që del nga seksioni kritik do të vendosë
lock=false ose waiting[j]=false. Të dyjat i lejojnë procesit që tenton, të hyjë në seksionin kritik.
Për të vërtetuar pritjen e kufizuar, do të cekim se kur procesi largohet nga seksioni i tij
kritik, ai e kontrollon fushën waiting me rradhë ciklike (i+1, i+2, ..., n-1, 0, ..., i-1). Në bazë të
kësaj renditjeje, ai e përcakton procesin e parë që është në seksionin e tij hyrës (për të cilin vlen
waiting[j]=true) si proces të ardhshëm që do të hyjë në seksionin kritik. Cilido proces që është
duke pritur të hyjë në seksionin kritik do ta bëj këtë brenda n-1 rradhëve.
7.6 Semaforët
V(S): S:=S+1;
7.6.1 Përdorimi
repeat
P(mutex);
146
seksioni kritik;
V(mutex);
seksioni mbetës;
until false;
S1;
V(synch);
P(synch);
S2;
në procesin P2. Pasi synch është e inicializuar në 0, P2 do të ekzekutojë S2 vetëm pasi P1 ta thërret
V(synch), që është pas S1.
Të marrim një shembull më të komplikuar. Të marrim grafin e përparësisë nga figura 7.6
dhe programin gjegjës më poshtë:
var a, b, c, d, e, f, g: semaphores;
(vlera iniciale e të gjithë semaforëve është 0)
begin
parbegin
begin S1; V(a); V(b); end;
begin P(a); S2; S4; V(c); V(d); end;
begin P(b); S3; V(e); end;
begin P(c); S5; V(f); end;
begin P(d); P(e); S6; V(g); end;
begin P(f); P(g); S7; end;
parend;
end;
Të përkujtojmë se patëm thënë se grafi nga figura 7.6 nuk ka program gjegjës që përdorë
instruksionin konkurent. Siç po shihet nga ky shembull, me shtimin e semaforëve instruksioni
konkurent bëhet po aq i fuqishëm si edhe konstruksioni fork/join.
7.6.2 Implementimi
Dobësia kryesore e zgjidhjeve të dhëna deri tani për përjashtimin reciprok të proceseve,
147
është se të gjitha këto zgjidhje kërkojnë pritjen e zënë (ang. busy-waiting). Derisa një proces
është në seksionin e vet kritik, cilido proces tjetër që është duke tentuar të hyjë në seksionin e tij
kritik është duke u sjellur pa ndërprerje në seksionin e tij hyrës. Në sistemin real mutiprogramor,
ku një procesor i vetëm është i ndarë nga më shumë procese, kjo është problem i vërtetë. Pritja e
zënë humb pa nevojë cikluset e procesorit të cilat ndonjë proces tjetër do të ishte në gjendje ti
shfrytëzojë racionalisht.
Për të tejkaluar nevojën e pritjes së zënë, mund të modifikojmë definicionin e P dhe V
operacioneve mbi semaforë. Kur procesi e ekzekuton operacionin P në semafor dhe e gjen se
vlera e semaforit nuk është pozitive, ai duhet të presë. Në këtë moment, në vend se të pret duke u
sjellur në unazë të seksionit hyrës, procesi mund ta bllokojë vehten. Operacioni i bllokimit e bjen
procesin në gjendje të pritjes. Pas kësaj kontrolli i jepet planifikuesit të procesorit, i cili nga rreshti
i proceseve të gatshme e zgjedh një proces për ekzekutim.
Procesi i cili është i bllokuar duke pritur në semaforin S duhet të ristartohet me
ekzekutimin e operacionit V nga ana e ndonjë procesi tjetër. Procesi zgjohet me anë të
operacionit të zgjimit (ang. wakeup operation), që e ndërron gjendjen e procesit prej gjendjes i
bllokuar në i gatshëm dhe e vendos në rreshtin e proceseve të gatshme. (Nuk është e thënë se
procesori do ti jepet menjëherë këtij procesi të çbllokuar; kjo do të varet nga algoritmi i
planifikimit.)
Që ta implementojmë sipas këtij definicioni semaforin do ta deklarojmë si variabël e tipit
record (në Pascal) ose struct (në C). record ose struct janë tipe të përbëra të variablave. Një
variabël e tipit record mund të përmbajë më shumë variabla të të tipeve të thjeshta.
Çdo semafor ka vlerën integer dhe listën e proceseve. Kur procesi duhet të presë, ai do të shtohet
në listën e proceseve. Operacioni V e largon një proces nga lista e proceseve që presin dhe e
zgjon atë proces.
Operacionet mbi semaforë mund të definohen tani si:
148
të dhëna si thirrje sistemore themelore.
Derisa definimi klasik i semaforëve me pritje të zënë, është i tillë që nuk lejon që vlera e
semaforit të jetë negative, ky implementim i semaforëve lejon vlera negative për semafor. Nëse
vlera e semaforit është negative moduli i kësaj vlere paraqet numrin e proceseve që janë duke
pritur në atë semafor. Paraqitja e vlerës negative është rrjedhim i ndërrimit të renditjes së operaci
oneve të dekrementimit dhe testimit në implementimin e operacionit P.
Lista e proceseve mund të implementohet me anën e fushës për lidhje që ndodhet në çdo
bllok kontrollues të proceseve. Çdo semafor përmban një vlerë integer dhe treguesin në listën e
blloqeve kontrolluese të proceseve. Mënyra më e thjeshtë e shtimit të proceseve në listë do të
ishte I-fundit-që-hyn-i-pari-del (LIFO, steku), por kjo mënyrë mund të shkaktojë që disa procese
të mos aktivizohen kurr. Lista është më shpesh e imple-mentuar si rresht, ndërsa semafori
përmban treguesit në fillimin dhe fundin e rreshtit. Në përgjithësi, lista mund të ketë cilëndo
strategji të renditjes (FIFO, LIFO, prioritetin, etj.). Përdorimi korekt i semaforëve nuk varet nga
strategjia e veçantë e rreshtimit të listave të semaforëve.
Qështje kritike me semaforë është ekzekutimi i tyre atomik. Duhet të garantojmë se
asnjëherë dy procese nuk do të ekzekutojnë P ose V operacionin mbi të njejtin semafor në të
njejtën kohë. Kjo situatë paraqet problem të seksionit kritik dhe mund të zgjidhet në njërën nga
dy mënyrat e dhëna më poshtë.
Në rrethinë njëprocesorike (ku ekziston vetëm një procesor), mundemi thjesht të
ndalojmë ndërprerjet gjatë kohës së ekzekutimit të P dhe V operacioneve. Kjo skemë funksionon
në sistemet njëprocesorike për arsye se me ndalim të ndërprerjeve instruksionet nga proceset e
ndryshme nuk mund të ndërlidhen (kombinohen).
Në rrethinën shumëprocesorike kjo zgjidhje nuk bën. Instruksionet nga proceset tjera që
ekzekutohen në procesorë tjerë mund të ndërlidhen në ndonjë mënyrë arbitrare. Nëse hardveri
nuk ofron asnjë instruksion special, mund të zbatojmë cilëndo zgjidhje korekte softverike të
problemit të seksionit kritik (algoritmet 4, 5, 6 ose më lartë), në të cilin rast seksionin kritik
paraqesin procedurat P dhe V.
Duhet pranuar se me këtë definim të operacioneve P dhe V nuk e kemi eliminuar tërësisht
pritjen e zënë. Do të ishte më saktë të themi se në fakt, e kemi eliminuar pritjen e zënë nga hyrja
në seksionin kritik të programeve aplikative. Më tutje, e kemi kufizuar këtë vetëm në seksionet
kritike të operacioneve P dhe V që janë shumë të shkurtë (zakonisht jo më shumë se dhjetë
instruksione). Në këtë mënyrë, praktisht, pritja e zënë gati kur nuk paraqitet, e edhe nëse ndodh
kjo, atëherë zgjatë shumë shkurt. Derisa pritja e zënë mund të tolerohet te operacionet mbi
semaforë, në aplikacionet ku ekzekutimi i pjesës së kodit që i takon seksionit kritik mund të
zgjatë edhe disa orë, pritja e zënë do të ishte shumë joefikase.
149
konkret. Do të supozojmë se kemi n baferë, secili me kapacitet të ruajtjes së një informate.
Semafori mutex ofron përjashtimin reciprok qasje-ve baferëve. Semaforët full (të plotë) dhe
empty (të zbrazët) numrojnë respektivisht numrin e baferëve të plotë dhe të zbrazët.
parbegin
producer: repeat
...
prodhoje një element në nextp
...
P(empty);
P(mutex);
...
shtoje nextp në buffer
...
V(mutex);
V(full);
until false;
consumer: repeat
P(full);
P(mutex);
...
barte një el. nga buffer në nextc
...
V(mutex);
V(empty);
...
konsumo elementin nga nextc
...
until false;
parend;
end;
Vëreni simetrinë mes prodhuesit dhe konsumuesit. Kodi mund të interpretohet sikur prodhuesi
krijon baferë të plotë për konsumuesin, ose sikur konsumuesi prodhon baferë të zbrazët për
prodhuesin.
150
Një objekt, datotekë ose rekord, do të përdoret bashkarisht nga disa procese konkurente.
Disa nga këto procese do të dëshirojnë që vetëm ta lexojnë përmbajtjen e objektit të përbashkët,
ndërsa disa do të dëshirojnë ta ndërrojnë (pra, të lexojnë dhe të shkruajnë) përmbajtjen e tij.
Proceset që janë të interesuara vetëm për leximin e përmbajtjes së objektit do ti quajmë lexues, të
tjerët do ti quajmë shkrimtar. Nëse dy lexues i qasen të njejtit objekt në mënyrë simultane asgjë e
padëshiruar nuk do të ndodhë. Mirëpo, nëse një shkrimtar dhe disa procese tjera (lexues ose
shkrimtar) i qasen objektit njëkohësisht, gjithçka mund të ndodhë. Qasja e tillë konkurente do të
cenojë konditat e Bernsteinit.
Që këto vështirësi të evitohen, do të kërkojmë që shkrimtarët të kenë qasje ekskluzive
objektit të përbashkët. Ky problem i sinkronizimit i njohur si problemi i shkrimtarëve dhe
lexuesve është definuar dhe zgjidhur së pari nga Courtois [1971]. Prej atëherë shfrytëzohet për
testimin e gati secilit primitiv sinkronizues. Problemi ka disa varianta, secila me përdorimin e
prioriteteve. Varianta më e thjeshtë, e njohur si problemi i parë i lexuesve dhe shkrimtarëve,
kërkon që asnjë lexues nuk bën të lihet të presë, përveç në rastin kur shkrimtari e ka fituar lejen ta
përdorë objektin. Me fjalë të tjera asnjë lexues nuk bën të lihet të presë vetëm për shkak se një
shkrimtar është duke pritur. Problemi i dytë i lexuesve dhe shkrimtarëve shtron kërkesën që
menjëherë me të kaluar të një shkrimtari në gjendjen i gatshëm, duhet sa më shpejtë ti mundëso
het shkruarja. Me fjalë të tjera, nëse një shkrimtar është duke pritur ti qaset objektit asnjë proces i
ri i lexuesit nuk bën të fillojë leximin.
Duhet cekur se zgjidhja e cilitdo variant mund të shkaktojë paraqitjen e "vdekjes nga uria"
(ang. starvation). Në rastin e parë shkrimatrët mund të kenë uri, në të dytin lexuesit. Për këtë
arsye janë propozuar tjera variante të problemit. Do të japim zgjidhjen e variantit të parë.
Në zgjidhjen e problemit të parë të lexuesve dhe shkrimtarëve, proceset e lexuaesve
ndajnë këto struktura të të dhënave të përbashkëta:
Semaforët mutex dhe wrt janë të inicializuar në 1, ndërsa readcount në 0. Semafori wrt është i
përbashkët edhe për procesin e lexuesit edhe për procesin e shkrimtarit. Semafori mutex shërben
për të siguruar përjashtimin reciprok në momentin e azhurimit të variablës readcount. Readcount
numron sa procese janë momentalisht duke lexuar objektin. Semafori wrt shërben si semaforë për
përjashtimin reciprok të shkrimtarëve. Ai poahtu përdoret nga lexuesi i parë dhe i fundit që hyn
ose del nga seksioni kritik. Ky semaforë nuk përdoret nga lexuesit që hyjnë ose dalin derisa
lexuesit tjerë janë në seksionet e veta kritike.
Struktura e procesit të lexuesit është:
P(mutex);
readcount : readcount + 1;
if readcount = 1 then P(wrt);
V(mutex);
...
bëhet leximi
...
P(mutex);
readcount := readcount - 1;
if readcount = 0 then V(wrt);
V(mutex);
151
ndërsa struktura e përgjithshme e shkrimtarit është:
P(wrt);
...
bëhet shkruarja
...
V(wrt);
Vëreni se nëse shkrimtari është në seksionin e vet kritik dhe n lexues janë duke pritur, atëherë një
lexues do të rreshtohet në wrt, ndërsa n-1 lexues tjerë në mutex. Poashtu, kur shkrimtari të
ekzekuton V(wrt), mund të vazhdojmë ekzekutimin e cilitdo nga lexuesit që presin ose me
ekzekutimin e shkrimtarit të vetëm që pret. Zgjidhja varet nga planifikuesi.
Problemi i filozofëve që janë duke ngrënë është paraqitë dhe zgjidhur nga Dijkstra.
Problemi mund të definohet kështu. Pesë filozofë e kalojnë jetën duke menduar dhe duke
ngrënë. Filozofët rrinë pranë tavolinës së përbashkët, në të cilën janë 5 pjata dhe 5 piruj, të
shtruar si në figurën 7.9. Kur filozofi mendon ai nuk komunikon me kolegët e vet. Kohëpaskohe
filozofi untohet dhe tenton të merr dy piruj që i ka më afër (pirujt mes tij dhe fqinjëve të tij në të
djathtë dhe në të majtë). Filozofi mund ta ngrit vetëm nga një piru në një moment. Kuptohet, ai
nuk mund ta merr pirunin i cili është në duart e fqinjit të tij. Kur filozofi i uritur ti ketë në duar të
dy pirujtë, ai ha pa i lëshuar pirujt. Pasi të ngrën, filozofi i lëshon pirujt dhe fillon të mendoj
përsëri.
Një zgjidhje e thjeshtë nënkupton paraqitjen e secilit piru me një semafor. Filozofi do të
tentojë të merr pirunin me ekzekutimin e operacionit P në semafor. Piruni do të lirohet me
ekzekutimin e operacionit V mbi semafor. Pra, të dhënat e përbashkëta janë:
(është përdorë chopstick që është fjalë për të treguar shkopinjtë për të ngrënë, në vend të
shprehjes fork që përdoret për piru, për ti ikur paqartësive të mundshme) ku secili element i
chopstick është i inicializuar në vlerën 1. Struktura e filozofit i mund të përshkruhet si:
repeat
P(chopstick[i]);
P(chopstick[i+1 mod 5]);
...
ha
...
V(chopstick[i]);
V(chopstick[i+1 mod 5]);
...
mendo
...
until false;
Edhepse kjo zgjidhje garanton se dy filozof fqinjë nuk mund të ngrënë njëkohësisht, ajo
prapseprap duhet të refuzohet për shkak të mundësisë së ngujimit. Të supozojmë se të pestë
152
filozofët i merr uria në të njejtën kohë dhe secili ia ngjet pirunit të majtë. Të gjitha elementet e
chopstick janë tani zero. Kur cilido filozof tenton të merr pirunin e djathtë, do të suspendohet
përgjithmonë.
Për zgjidhjen e këtij problemi mund të përdorim ndonjërën prej zgjidhjeve të prezentuara
në vazhdim:
- Të lejojmë që më së shumti 4 filozofë të ulen njëkohësisht pranë tavolinës.
- Ti lejojmë filozofit ti merr pirujt vetëm kur të dytë janë në dispozicion (kjo duhet bërë në
kuadër të seksionit kritik).
- Të përdorim zgjidhjen asimetrike. Kjo do të thotë se filozofi tek e merr së pari pirunin e
tij të majtë e pastaj të djathtin, ndërsa filozofi çift së pari e merr pirunin e djathtë e pastaj pirunin e
majtë.
Së fundit cilado zgjidhje e pranueshme duhet të sigurojë që asnjë nga filozofët të mos
vdesë nga uria. Zgjidhja e problemit që nuk lejon ngujimin nuk e eliminon me çdo kusht
mundësinë e vdekjes nga uria.
153
Nëse proceset P dhe Q dëshirojnë të komunikojnë, ata duhet të dërgojnë dhe të pranojnë
porosi nga njëri tjetri. Që ta bëjnë këtë mes tyre duhet të ekzistojë lidhja komunikuese. Kjo lidhje
mund të implementohet në mënyra të ndryshme. Nuk do të ndalemi në qështjet e implementimit
fizik të lidhjes (memoria e përbashkët ose busi hardverik), por më shumë në qështjet e
implementimit logjik, siç janë p.sh. cilësitë logjike të lidhjes. Disa probleme themelore të
implementimit janë:
- Si realizohen lidhjet?
- A ka mundësi që lidhja të shoqërohet me më shumë se dy procese?
- Sa lidhje mund të ketë mes çdo çifti të proceseve?
- Sa është kapaciteti i lidhjes? Me fjalë tjera, a ka lidhja far hapësire baferike? Nëse po, sa?
- Çfarë është madhësia e porosive? A mundet lidhja të pranojë porositë me madhësi të
ndryshueshme apo fikse?
- A është lidhja njëkahëshe apo dykahëshe? Do të thotë, nëse lidhja ekziston ndërmjet P
dhe Q, a munden porositë të shkojnë në një kahje (p.sh. vetëm prej P kah Q) apo në të dy kahjet?
Definicioni i njëkahshmërisë duhet të jetë më preciz i definuar, pasi që lidhja mund të jetë
e shoqëruar me më shumë se dy procese. Prandaj, do të themi se lidhja është njëkahore, vetëm
nëse çdo proces i lidhur në të mundet ose vetëm të dërgojë ose vetëm të pranojë, por jo të dyjat
dhe kur çdo lidhje ka së paku një proces pranues të lidhur në te.
Ekzistojnë disa metoda për implementimin logjik të lidhjes dhe operacioneve
send/receive:
- Komunikimi direkt ose indirekt.
- Dërgimi procesit ose në "kuti të postës" (ang. mailbox).
- Komunikimi asimetrik ose simetrik.
- Baferimi automatik ose eksplicit.
- Dërgimi i kopjes ose referencës.
- Porositë me madhësi fikse ose të ndryshueshme.
7.8.1 Emërimi
Komunikimi direkt
Te komunikimi direkt secili proces që dëshiron të pranojë ose të dërgojë një porosi duhet
në mënyrë eksplicite të emrojë pranuesin ose dërguesin e porosisë. Në këtë skemë primitivet send
dhe receive janë të definuara si (ang. message, shq. porosi):
154
type item = ...;
var nextp, nextc: item;
parbegin
producer: repeat
...
prodhoje një element në nextp
...
send (consumer, nextp);
until false;
consumer: repeat
receive(producer, nextc);
...
konsumoje një element nga nextc
...
until false;
parend;
Komunikimi indirekt
Te komunikimi indirekt porositë dërgohen në dhe pranohen nga "kutia e postës" (ang.
mailbox) ose porti. Këtë kuti mund ta marrim si një objekt në të cilin mund të vendosen porositë
nga proceset dhe prej të cilit proceset mund ti marrin porositë. Çdo kuti e ka emrin me të cilin
dallohet. Në këtë skemë procesi mund të komunikojë me ndonjë proces përmes disa kutive të
ndryshme. Dy procese mund të komunikojnë vetëm nëse kanë kutinë e përbashkët. Primitivet
send dhe receive janë të definuara si:
155
- Mes çdo çifti të proceseve që komunikojnë mund të ekzistojnë më shumë lidhje, që
secila veç e veç i përgjigjet një kutie.
- Lidhja mund të jetë njëkahshe ose dykahëshe.
Të supozojmë tani se proceset P1, P2 dhe P3 ndajnë kutinë A. Procesi P1 dërgon porosinë
në A, derisa P2 dhe P3 secili ekzekutojnë operacionin receive nga A. Kush do ta pranojë porosinë
nga A? Pyetja mund të ketë zgjidhje të ndryshme:
- Mund të lejojmë që lidhja të shoqërohet me më së shumti dy procese.
- Mund të lejojmë vetëm një procesi në një moment kohor të ekzekutojë operacionin
receive.
- Mund të lejojmë që sistemi arbitrarisht të zgjedhë procesin që do ta pranojë porosinë
(pra, ose P1 ose P2, por jo të dy). Procesi mund t'ia tregojë identitetin e pranuesit dërguesit.
Pronësia e kutive
Kutia mund të jetë pronë e procesit ose e sistemit. Nëse kutia është pronë e procesit (që
do të thotë se kutia i është bashkangjitur procesit, ose është pjesë e procesit), atëherë do të bëjmë
dallim mes pronarit (i cili mundet vetëm të pranojë porosi përmes kësaj kutie) dhe shfrytëzuesit të
kutisë (që mundet vetëm të dërgojë porosi në kuti). Pasi secila kuti e ka pronarin unik, nuk do të
ketë paqartësi se kush do ta pranojë porosinë e dërguar. Me të përfunduar të procesit që posedon
kutinë, kutia zhduket. Cilido proces që në vazhdim dërgon porosi në këtë kuti, duhet të jetë i
informuar se kutia më nuk ekziston.
Ka disa mënyra për caktimin e pronarit dhe shfrytëzuesve të kutisë së caktuar. Një
mundësi është që ti lejohet procesit të deklarojë variabla të tipit mailbox. Procesi që e deklaron
një kuti (variabël mailbox) është edhe pronar i saj. Çdo proces tjetër që e di emrin e kësaj kutie
mund ta përdorë. Poashtu është e mundur të deklarohet kutia si e përbashkët e pastaj nga jashtë
të tregojmë identitetin e pronarit.
Në anën tjetër kutia që është pronë e sistemit operativ, ka ekzistencë të pavarur. Kutia e
tillë nuk është e bashkangjitur asnjë procesi. Sistemi operativ ka mekanizmin që i lejon procesit:
- Të krijojë kuti të re.
- Dërgojë dhe pranojë porosi nëpër kuti.
- Të shkatrojë kutinë.
Procesi që e krijon kutinë është pronari i saj i nënkuptuar. Në fillim, pronari është i vetmi
proces që mund të pranojë porosi përmes kësaj kutie. Mirëpo, pronësia dhe privilegjet e pranimit
të porosive mund t'iu barten proceseve tjerë përmes thirrjeve gjegjëse sistemore. Kjo na
mundëson të kemi pranues të shumëfishtë për një kuti. Shfrytëzimi i përbashkët i një kutie mund
të jetë rezultat i mundësisë së proceseve për të krijuar procese të reja. Procesi Q i krijuar nga
procesi P mund ta ndajë me procesin P kutinë e krijuar nga procesi P. Pasi të gjitha proceset me
të drejtë qasjeje kutisë munden më në fund të përfundojnë, pas një kohe kutia mund të jetë e
paarritshme për cilindo proces. Në këtë rast sistemi operativ do të rikthejë hapësirën e zënë nga
kutia.
7.8.2 Baferimi
Kapaciteti
156
Lidhja ka njëfarë kapaciteti që përcakton sa porosi munden përkohësisht të ndodhen në
të. Kjo cilësi mund të trajtohet si rresht i porosive të bashkangjitura lidhjes. Parimisht, ekzistojnë
tri mënyrë për implementimin e kësi lloj rreshti:
- Kapaciteti zero. Rreshti ka gjatësinë maksimale 0. Rrjedhimisht lidhja nuk mund të
ketë asnjë porosi që do të rri në te. Në këtë rast dërguesi duhet të presë derisa pranuesi ta pranon
porosinë. Proceset duhet të jenë të sinkronizuar në mënyrë që transferi të kryhet. Ky sinkronizim
quhet rendezvous (fr. rendezvous shq. takim).
- Kapaciteti i kufizuar. Rreshti ka gjatësi të fundme n; pra më së shumti n porosi mund
të qëndrojnë në te. Nëse rreshti nuk është i plotë në momentin e dërgimit të porosisë, porosia do
të vendoset në rresht (ose duke u kopjuar, ose duke ruajtur treguesin në porosi) e dërguesi mund
të vazhdojë ekzekutimin pa pritje. Megjithatë, lidhja ka kapacitet të fundëm. Nëse lidhja është e
plotë, dërguesi duhet të suspendohet derisa të krijohet vend në rresht.
- Kapaciteti i pakufizuar. Rreshti është potencialisht i pafundshëm; pra, çfarëdo numër i
porosive mund të qëndrojnë në te. Dërguesi nuk do të vonohet asnjëherë.
Rasti i kapacitetit zero është i njohur edhe si sistem i porosive pa baferim; rastet tjera
ofrojnë baferim automatik.
Do të cekim se në rastet e kapacitetit zero, procesi me të përfunduar të operacionit send
nuk e di se a ka mbërri porosia në cakun e vet. Nëse kjo informatë është e qenësishme për
llogaritje, procesi i dërguesit duhet në mënyrë eksplicite të komunikojë me pranuesin për të marr
vesh a ka mbërri porosia. Për shembull, të supozojmë se procesi P ia dërgon procesit Q porosinë
dhe mund të vazhdojë ekzekutimin vetëm pasi porosia të jetë pranuar. Procesi P do të ekzekutojë
sekuencën:
e procesi Q do të ekzekutojë:
Porositë
m: mailbox[n] of item;
157
Rastet speciale
Porositë e humbura
Porosia nga procesi P dërguar procesit Q mund të humbet diku në rrjetën komunikuese
për shkak të defektit të linjës komunikuese ose hardverit të kompjuterit. Ekzistojnë tri metoda
themelore për trajtimin e këtij rasti.
1. Sistemi operativ është përgjegjës për detektimin e kësaj ngjarjeje dhe për ridërgimin e
porosisë.
2. Procesi dërgues është përgjegjës për detektimin e kësaj ngjarjeje dhe për ridërgimin e
158
porosisë, nëse këtë dëshiron ta bëjë.
3. Sistemi operativ është përgjegjës për detektimin e kësaj ngjarjeje; ai e njofton procesin
dërgues se porosia është humbur. Procesi dërgues mund të vazhdojë si të dojë.
Nuk është gjithmonë e domosdoshme të detektohen porositë e humbura. Shfrytëzuesi
duhet të përcaktojë (duke ia bërë të ditur sistemit operativ, ose duke e programuar vetë) se a
duhet apo nuk duhet bërë një kontroll të tillë.
Si detektohet humbja e porosisë? Mënyra më e zakonshme është përdorimi i time-outëve.
Kur të dërgohet porosia, porosia e përgjegjës që vërteton pranimin e porosisë, dërgohet
gjithmonë prapa. Sistemi operativ ose procesi dërgues mund të specifikojnë intervalin kohor
brenda të cilit do të presin arrdhjen e vërtetimit. Në kjo kohë kalon para se të vie vërtetimi sistemi
operativ ose procesi dërgues do të supozojnë se porosia është humbur. Është e mundur në këtë
rast që porosia nuk është humbur, por i është dashur pak më shumë kohë të udhëtojë nëpër rrjetë.
Në këtë rast mund të kemi porosi të shumëfishta që udhëtojnë nëpër sistem. Ekziston mekanizmi
që do ti dallojë këto porosi.
Porositë e shtrembëruara
Porosia mund të mbërrijë në cakun e saj, por mund të jetë e shtrembëruar për shkak të
zhurmave në kanalin komunikues, ta zëmë. Ky rast është i ngjashëm me rastin e porosive të
humbura. Ose sistemi operativ do të ritransmetojë porosinë ose do ta njoftojë procesin për këtë.
Për detektimin e gabimeve të tilla përdoret kontrolli i paritetit ose CRC (ang. Cyclic Redundancy
Check, shq. kontrolli ciklik i redudancës).
159