Download as pdf or txt
Download as pdf or txt
You are on page 1of 159

1.

Hyrje

Sistemi operativ është program që shërben si ndërmjetsues mes shfrytëzuesit të


kompjuterit dhe hardverit të kompjuterit. Qëllimi i sistemit operativ është që të krijojë rrethinën
në të cilën do të ekzekutohen programet e shfrytëzuesit. Pra, mund te thuhet që qëllimi primarë i
sistemit operativ është që ta bëjë kompjuterin të përshtatshëm për shfrytëzim. Qëllimi i dytë i
sistemit operativ është që të mundësojë shfrytëzimin efikas të hardverit të kompjuterit. Që të
kuptohet më lehtë se çka janë sistemet operative është me rëndësi të mësohet se si janë zhvilluar.
Si janë zhvilluar sistemet operative dhe cilat kanë qenë arsyet e një zhvillimi të tillë, do të
tregojmë në vazhdim.
Poashtu do të japim disa koncepte themelore të nevojshme për diskutimin e probleve në kapitujt
vijues.

1.1 Çka është sistemi operativ ?

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.

1.2 Sistemet e hershme

Në fillim ka ekzistuar vetëm hardveri i kompjuterit. Programeri, në atë kohë edhe


operatorë i kompjuterit, e shkruante programin e pastaj direkt nga konzola e kompjuterit së pari e
vendoste programin në kompjuter duke shfrytëzuar ndërprerësit ose shiritin me vrima. Duke
shtypur disa pulla kompjuterit i është dhënë adresa e instruksionit të parë. Në të njejtën mënyrë,
pra me shtypjen e disa pullave tjera nga konzola e kompjuterit është startuar ekzekutimi i
programit. Rrjedha e programit, kontrolli i gabimeve dhe përmbajtja e memories dhe regjistrave
është kontrolluar në konzolë që ka pasë një numër të madh të diodave për përcjelljen e këtyre
informatave. Rezultati i përpunimit është dhënë në shiritin me vrima e pastaj është shtypë në
makina të ngjashme me teleprinterë.
Me kohë është paraqitur hardveri dhe softveri i ri. Janë paraqitur lexuesit e kartelave me
vrima, printerët linjorë, dhe shiritat magnetik. Për lehtësim të programimit janë krijuar aemblerët,
loaderët dhe linkerët. Janë paraqitë edhe libraritë e funksioneve më të kërkuara. Në këtë mënyrë
funksionet kanë mund vetëm të kopjohen, nuk ka qenë më e nevojshme të shkruhen secilën herë.
Njësitë e reja hyrëse dalëse kanë shtru nevojën që edhe për to veç e veç të shkruhen programet që
kontrollojnë punën e tyre. Këto programe njihen si drajver (ang. driver shq. vozitës, udhëheqës,
kontrollues) të njësive. Drajveri i ka informatat se si duhet të shfrytëzohen baferët (ang. buffer
shq. memorie që shërben për sinkronizimin e punës së dy tipeve të ndryshme të memories ose për
sinkronizimin e punës së procesorit e memories ose elementeve tjera të sistemit kompjuterik,
mund ta quajmë edhe memorie pranuese ose ndërmjetsuese, e realizuar përmes regjistrave ose
memories konvencionale operative), regjistrat, bitat kontrollues dhe bitat e statusit të njësisë së
posaçme hyrëse-dalëse. Çdo lloj i njësisë hyrëse-dalëse e ka drajverin e vet. Aksioni i thjeshtë i
leximit të karakaterit nga shiriti magnetik mund të përmbajë në vehte sekuencën e operacioneve
specifike për atë njësi hyrëse-dalëse. Që ky kod të mos shkruhet secilën herë, për çdo njësi janë
shkruar drajverët përkatës e pastaj janë shpërndarë përmes librarive të programeve të tilla.
Më vonë janë paraqitë gjuhët e larta programore dhe kompajlerët për këto gjuhë. Kjo ka
lehtësuar në masë të madhe programimin, por e ka bërë shfrytëzimin e kompjuterit më kompleks.
Numri i operacioneve përcjellëse që duhet të kryheshin u rrit dukshëm për shkak të nevojës që
tani në memorien e kompjuterit duhet të mbusheshin përveç programit burimor edhe kompajleri
për gjuhën programore të përdorur (në fiilim më së shpeshti fortran) dhe asembleri. Çdo
operacion i tillë ishte i përcjellë me montimin dhe çmontimin e shiritave të ndryshëm magnetik që
përmbanin këto programe në njësinë e shiritave. E gjithë kjo shpenzonte kohën e çmuar të
kompjuterit.

1.3 Monitori i thjeshtë

Një mundësi e zvoglimit të kohës së nevojshme për operacionet përcjellëse manuale me


njësi ka qenë angazhimi i operatorëve profesional, detyra e të cilëve ishte që programet e
përgatitura nga programeri t'i vendosin në kompjuterë, t'i startojnë dhe të kryejnë të gjitha
operacionet manuale të nevojshme me njësi.

3
Fig.1.2 Vendosja në memorie e monitorit rezident

Që edhe më shumë të zvoglojnë kohën e nevojshme për kryerjen e punëve përcjellëse


udhëheqësit e sistemeve kompjuterike vendosën që aplikimet me kërkesa të njejta ose të
ngjashme t'i përpunojnë në grup. Nëse është dashur të kryhet një punë në Fortran, një në Cobol e
pastaj prap një tjetër në Fortran, secila prej tyre e përcjellë me operacione manuale gjegjëse, të
marrim vetëm vendosjen e shiritave me kompajlerët e posaçëm, numri i operacioneve nuk ka
qenë i neglizhueshëm. Përpunimi në grup nënkupton se në këtë rast të posaçëm, së pari do të
kryheshin punët në Fortran e pastaj ajo punë që kërkon angazhimin e kompajlerit për Cobol. Në
këtë mënyrë është eliminuar një grup i operacioneve përcjellëse manuale për kryerjen e punës që
kërkonte kompajlerin e Fortranit. E njejta procedurë është përdorë nëse punët që duhet të
kryheshin kanë pasë kërkesa të njejta për njësi hyrëse-dalëse.
Por në rast se programi që ekzekutohej kishte gabim, puna ndërprehej, dhe në vazhdim
nëse ishte e nevojshme duhej të kryheshin operacionet e nevojshme për detektimin e gabimit, siç
është leximi i përmbajtjes së memories dhe regjistrave. Pas kësaj në kompjuter vendosej
aplikacioni i dytë dhe startohej përsëri kompjuteri. Të gjitha këto ishin të përcjella me operacione
siç është montimi dhe çmontimi i shiritave, përgatitja e lexuesit të kartelave etj. Gjatë gjithë kësaj
kohe njësia qendrore nuk bënte asgjë.
Që koha e mosshfrytëzimit të njësisë qendrore të zvoglohet është paraqitë dhe realizuar
ideja e sekuencimit automatik të punëve. Kjo ka qenë fillimi i sistemeve operative. Ajo që është
dashtë ka qenë procedura e shkurtë për kalim prej një pune në tjetrën. Fjala është për monitorin
rezident, program i vogël që është gjithnjë i pranishëm në memorien operative të kompjuterit.
Me kyçjen e kompjuterit kontrolli i është dhënë monitorit rezident i cili ia ka bartë
kontrollin programit ekzekutimi i të cilit ka filluar. Me përfundimin e programit, në mënyrë të

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.

1.5 Puna off-line

Edhepse me kohë shpejtësia e njësive hyrëse-dalëse u rrit, për shkak të përparimit të


teknologjisë shpejtësia e njësisë qendrore u rritë edhe më shumë.
Për të zgjidhur këtë problem njësia qendrore nuk i lexonte të dhënat direkt nga lexuesi i
kartelave, por nga ndonjë njësi më e shpejtë, në rastin më të shpeshtë nga shiriti magnetik.
Përmbajtja e kartelave për më shumë punë së pari bartej në shirit deri sa të plotësohej kapaciteti i
tij. Gjatë shtypjes njësia qendrore nuk komunikonte me shtypësin direkt por të dhënat dalëse i
shkruante në shirit. Bartja e të dhënave nga kartelat në shirit dhe nga shiriti në shtypës bëhej
jashta përpunimit kryesor, ose off-line. Për të bërë këtë, njësive hyrëse dalëse u shtoheshin njësi

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

Baferimi është një zgjidhje që tenton të zvoglojë disproporcionin mes shpejtësive të


njësive të ndryshme. Pasi qëllimi është që njësia qendrore të jetë sa më shumë e zënë me punë,
menjëherë sa të jetë kryer operacioni i hyrje-daljes dhe para se njësia qendrore të fillojë
përpunimin e të dhënave të lexuara, njësisë qendrore i urdhërohet që të fillojë menjëherë operaci­
onin e ardhshëm të hyrje-daljes. Në këtë mënyrë edhe njësia qendrore edhe njësia hyrëse-dalëse
do të jenë të zëna me punë. Derisa të zgjasë përpunimi i grupit të parë të të dhënave njësia hyrëse-
dalëse mund ta ketë kryer leximin e grupit të dytë të të dhënave dhe kjo do të mundësojë që njësia
qendrore pa pritje të fillojë përpunimin e tyre.
Gjatë operacionit të daljes së të dhënave njësia qendrore do t'i vendosë të dhënat në bafer,
që do të lexohet nga njësia dalëse, kur ajo të jetë e gatshme për këtë.

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

Problemet me shirita magnetik në masë të madhe u zbutën me fillimin e përdorimit të


disqeve. Për shkak se te sistemi i disqeve ka mundësi që kokat lexuese me shpejtësi të madhe të

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

Baferimi mundëson përputhjen kohore të hyrje-daljes së një pune me llogaritjet e


nevojshme për kryerjen e saj. Përparësia e spulingut është se spulingu mundëson përputhjen
kohore të operacionit të hyrje-daljes së një pune me llogaritjet e nevojshme të më shumë punëve.
Edhe në sistemet më të thjeshta spulingu mundëson që dalja e një pune të shtypet derisa zgjatë
hyrja e një pune tjetër, e krejt kjo në të njejtën kohë kur kryhen llogaritjet për punët tjera.
Spulingu në llogari të pak hapësirës në disk dhe disa tabelave i mban njësitë hyrëse-dalëse
dhe njësinë qendrore të zëna me punë të shumtën e kohës. Kjo vlen posaçërisht nëse kemi të
bëjmë me një përzierje të punëve (ang. job mix) të orientuara kah hyrja-dalja dhe të punëve të
orientuara më shumë në llogaritje.
Në fund të fundit, si rezultat të spulingut do të kemi grupin e punëve të cilat, pasi që të
dhënat hyrëse të tyre të jenë lexuar, presin që të ekzekutohen. Kjo i jep mundësi sistemit operativ
që nga grupi i punëve (ang. job pool) të zgjedhë njërën e cila e para do të ekzekutohet, me
qëllim të rritjes së efikasitetit të shfrytëzimit të njësisë qendrore. Deri sa nuk kanë hyrë në
përdorim disqet, nuk ka pasë mundësi që punët të ekzekutohen me rend i cili ka ndryshuar nga
rendi i vendosjes së tyre në njësinë hyrëse (lexuesi i kartelave ose shiriti magnetik). Mirëpo, prania
e më shumë punëve njëkohësisht në njësi me qasje direkte, siç është disku, mundësoi planifiki­
min e punëve (ang. job scheduling).

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ë.

Fig.1.5 Shpërndarja e memories për sistemin multiprogramor

Sistemet operative multiprogramore janë sisteme të sofistikuara. Në mënyrë që të kemi


më shumë punë të gatshme për ekzekutim është e nevojshme ti kemi të gjitha ato të vendosura
njëkohësisht në memorie. Kjo në anën tjetër sjell si nevojë që sistemi operativ të ketë ndonjë
formë të planifikimit të shfrytëzimit të memories. Pasi do të duhet të vendoset se cilat punë do
të ekzekutohen në ndonjë moment kohorë duhet të ekzistojë në kuadër të sistemit operativ,
mekanizmi i përpunuar i vendosjes se cili nga aplikacionet do të ekzekutohet. Sistemet operative
multiprogramore duhet poashtu të mundësojnë planifikimin e shfrytëzimit të njësive të sistemit
mes aplikacioneve të ndryshme, të zgjedhin problemet e arbitrimit mes aplikacioneve që
konkurojnë për njësi të njejta dhe të ofrojnë mbojtjen e aplikacioneve dhe resurseve të sistemit
nga keqpërdorimet.

9
1.9 Time sharing sistemet

Cilësi e beç sistemeve kompjuterike ka qenë ekzekutimi i punëve të ngjashme në grup.


Kjo ka qenë pasojë e karakteristikave të lexuesve të kartelave dhe shiritave. Me paraqitjen e
disqeve nuk ka qenë më e obligueshme që punët të ekzekutohen sipas rendit të vendosjes. Kjo ka
shkaktuar që në njëfarë masë të ndërrojë koncepti i beç përpunimit.
Beç sistemi operativ zakonisht e lexon rrjedhën e punëve të veçanta që duhet kryer, të
ndara me kartela kontrolluese. Pasi ta ketë kryer përpunimin e kërkuar, kompjuteri të shumtën e
rasteve në printer ose në ndonjë njësi tjetër dalëse do të jep rezultatet e kërkuara. Cilësi kryesore
e beç sistemeve operative është mungesa e interaksionit të shfrytëzuesit dhe aplikacionit
gjatë ekzekutimit të tij. Problemet që paraqiten për shkak të pamundësisë së interaksionit mes
shfrytëzuesit dhe aplikacionit të tij shkaktojnë që programeri të jetë shumë më i kujdesshëm gjatë
programimit, të zvoglojë në minimum gabimet e mundshme. Për punët që zhvillohen në disa faza,
fillimi i njërës fazë do të mund të varej nga përfundimi suksesshëm i fazës paraprake. Është shumë
vështirë të planifikohen të gjitha mundësitë e përfundimit të fazës paraprake të ekzekutimit.
Programeri nuk ka informatë se si sjellet programi nëpër të gjitha fazat e ekzekutimit, gjë që
vështirëson detektimin e gabimeve eventuale.
Sistemi operativ interaktiv mundëson komunikimin on-line mes kompjuterit dhe
shfrytëzuesit. Shfrytëzuesi ia jep direkt instruksionet sistemit operativ ose aplikacionit dhe i
pranon menjëherë përgjegjet nga ai. Hyrja e komandave bëhet zakonisht me tastierë e jo përmes
kartelave me vrima. Përgjegjen e vet sistemi operativ ose aplikacioni e japin në monitor ose
shtypës. Kjo mundëson eksperimentimin me program dhe përcjelljen e sjelljes së tij për të dhëna
të ndryshme hyrëse.
Beç sistemet janë të përshtatshëm për ekzekutimin e punëve të mëdha për të cilat nuk ka
nevojë të ekzistojë ndonjë komunikim i drejtëpërdrejtë me shfrytëzuesin. Shfrytëzuesi e përgatit
aplikacionin, e starton ekzekutimin ose e autorizon operatorin që ta bëjë këtë dhe zakonisht vjen
më vonë që të merr rezultatet e përpunimit. Punët interaktive përbëhen nga numër i madh i
veprimeve të shkurta, me ç'rast rezultatet e një komande nuk munden gjithnjë të parashihen.
Shfrytëzuesi e jep komandën dhe pret përgjegjen nga sistemi. Në këtë rast, është me rëndësi koha
e përgjegjes së sistemit, që duhet të jetë e shkurtë dhe nuk guxon të jetë më shumë se disa
sekonda.
Time sharing sistemet operative i japin secilit shfrytëzues një pjesë të kohës së
kompjuterit. Shfrytëzuesit e sistemeve të tilla kanë në dispozicion hisen e tyre të kohës së njësisë
qendrore të kompjuterit. Që kjo të realizohet shfrytëzohet planifikimi i punës së njësisë qendrore
dhe multiprogramimi. Aplikacionet e shfrytëzuesve ndodhen në memorien operative. Kur
programi të ekzekutohet ai zakonisht ekzekutohet një kohë të shkurtër deri në momentin kur të
paraqitet nevoja për kryerjen e hyrje-daljes. Që njësia qendrore të mos rrijë e papunë duke pritur
kryerjen e këtij operacioni, sistemi operativ ia jep njësinë qendrore për shfrytëzim ndonjërit nga
programet tjera në memorie.
Time sharing sistemi operativ u ofron shfrytëzuesve që njëkohësisht të shfrytëzojnë
resurset e kompjuterit duke ia dhënë secilit një pjesë të kohës së njësisë qendrore. Pasi ky interval
kohor është i shkurtë, i rendit disa dhjetra ose disa qindra mikrosekonda, shfrytëzuesit kanë
përshtypjen se vetëm ata kanë në dispozicion të gjitha resurset e kompjuterit, ndërkohë që ai
mund të jetë i angazhuar nga më shumë sish njëkohësisht.

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.

1.10 Sistemet e kohës reale

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.

1.11.1 Mbrojtja e hyrje-daljes

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

Që mbojtja e hyrje-daljes të jetë komplete nuk guxojmë të lejojmë që programi i


shfrytëzuesit të kontrollojë punën e kompjuterit në modin sistemor. Secilën herë që të paraqitet
trepi kompjuteri do të kalojë në modin sistemor dhe do të ekzekutojë rutinën, adresa fillestare e të
cilës është e definuar me vektorin e ndërprerjes. Të supozojmë se programi i shfrytëzuesit gjatë
ekzekutimit të vet, e vendos në vektorin e ndërprerjes një adresë nga fusha adresore e vet, që do
ta fshijë adresën ekzistuese. Tani me paraqitjen e trepit, përmes adresës së modifikuar, programi i
shfrytëzuesit do ta fitojë kontrollin mbi kompjuterin në modin sistemor.
Duhet pra, të ndalojmë modifikimin e vektorëve të ndërprerjes nga ana e programeve të
shfrytëzuesve. Poashtu duhet që nga ndikimi i shfrytëzuesit të mbrojmë edhe kodin e rutinave të
cilat shërbejnë ndërprerjet. Nëse e lejojmë modifikimin e këtyre rutinave, programet e
shfrytëzuesit do të mund ta ndrojnë në atë mënyrë kodin e tyre, ashtu që përmes instruksioneve të
kërcimit nga rutinat shërbyese të modifikuara, që ekzekutohen në modin sistemor, të kalojnë në
programin e tyre dhe në këtë mënyrë përsëri të fitojnë kontrollin mbi kompjuter që punon në
modin sistemor.
Zgjidhje e këtij problemi është mbrojtja e hapësirës memorike ku ndodhen vektorët e
ndërprerjeve dhe rutinat shërbyese të ndërprerjeve. Kjo mbrojtje bëhet duke shfrytëzuar hardverin
e kompjuterit.
Në shumicën e rasteve vektorët e ndërprerjeve dhe rutinat e përmendura zënë vend në
adresat e ulta të memories ndërsa programet e shfrytëzuesve vendosen në hapësirën memorike
me adresa më të mëdha. Që të mbrohet pjesa e ndieshme e memories mjafton të shfrytëohet një
regjistër kufizues që përmban adresën kufitare të zonës së mbrojtur. Mbrojtja realizohet ashtu që
çdo adresë e gjeneruar në modin e shfrytëzuesit krahasohet me përmbajtjen e këtij regjistri. Nëse
adresa e gjeneruar i takon zonës së mbrojtur, paraqitet trepi, kompjuteri kalon në modin sistemor,
ndërpren ekzekutimin e programit që ka gjeneruar adresën jolegale dhe eventualisht starton
ndonjë program tjetër. Në këtë mënyrë sigurohemi që të dhënat në pjesën e mbrojtur të memories
nuk munden të ndërrohen me qëllim ose pa qëllim.

14
Fig.1.8 Mbrojtja hardverike e adresave të monitorit rezident

Përmbajtja e regjistrit kufizues mund të ndërrohet vetëm me instruksion të privilegjuar


nga ana e sistemit operativ, gjatë punës së sistemit në modin sistemor.
Regjistri kufizues mjafton që zona sistemore e memories të mbrohet nga programet e
shfrytëzuesve, por nuk mjafton që t'i mbrojë programet e shfrytëzuesve nga njëri tjetri. Që kjo të
jetë e mundshme na nevojiten regjistra që do të tregojnë kufirin e poshtëm dhe të epërm të
adresave që mund të gjenerohen nga programi i mbrojtur në këtë mënyrë. Çdo adresë e gjeneruar
do të krahasohet më tutje me përmbajtjen e këtyre regjistrave. Kuptohet se instruksionet për
modifikimin e përmbajtjes së këtyre regjistrave duhet të jenë instruksione të privilegjuara.

Fig.1.9 Tentimi i ekzekutimit të programit me zhvendosje të kufirit

Fig.1.10 Dy regjistra të kufirit e definojnë hapësirën adresore logjike

15
1.11.3 Mbrojtja e njësisë qendrore

Gabimet në programet e shfrytëzuesve mund të shkaktojnë që kompjuteri të bllokohet


duke ekzekutuar instruksionet në unazë të pafundshme. Ky problem zgjidhet me aplikimin e
tajmerit (ang. timer, time shq. kohë). Tajmeri mund të ndërprejë kompjuterin pas kalimit të
periudhës së caktuar kohore. Tajmeri realizohet përmes orës dhe një numruesi. Vlera e numruesit
vendoset nga sistemi operativ. Me çdo tik-tak të orës dekrementohet vlera e numruesit. Kur
numruesi të ketë vlerën zero gjenerohet ndërprerja e tajmerit e cila shkakton që sistemi operativ
të merr kontrollin mbi kompjuter. Instruksionet që punojnë me tajmer janë instruksione të
privilegjuara.

16
2. Shërbimet e sistemit operativ

Sistemi operativ siguron rrethinën në të cilën do të ekzekutohen programet. Pasi sistemi


operativ është i vetmi i cili mund të kryej operacionet e harje-daljes, programet e shfrytëzuesve do
të kërkojnë që sistemi operativ t'i bëjë këto punë për ta. Do të shohim se cilat shërbime i ofron
sistemi operativ dhe në çfarë mënyre e bënë këtë.

2.1 Llojet e shërbimeve

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.

2.2 Këndvështrimi i shfrytëzuesit

Shërbimet e sistemit operativ realizohen në mënyra të ndryshme. Dy mënyrat kryesore


janë thirrjet sistemore dhe programet sistemore.

17
2.2.1 Thirrjet sistemore

Niveli më bazik i shërbimeve të sistemit operativ realizohet përmes thirrjeve sistemore.


Thirrjet sistemore janë ndërmjetsues mes sistemit operativ dhe programit që ekzekutohet. Thirrjet
sistemore mund të ekzekutohen si instruksione asemblerike. Përshkrimi dhe parametrat e tyre
ndodhen në çdo doracak për gjuhën asemblerike.

Kontrolli i proceseve dhe punëve

Programi që ekzekutohet duhet të ketë mundësi që të ndërprejë ekzekutimin e vet në


mënyrë normale ose jonormale. Thirrjet sistemore që i përgjigjen këtyre operacioneve janë
zakonisht end dhe abort. Nëse programi e detekton gabimin, mund të jetë e nevojshme që të
definojë nivelin e gabimit. Zakonisht sa më serioz që të jetë gabimi numri me të cilin shprehet
niveli i gabimit është më i madh. Kjo mundëson që edhe përfundimin normal të programit ta
definojmë si përfundim jonormal të programit me nivel të gabimit 0 (zero).
Procesi ose puna që ekzekutohet mund të kërkojë që të vendosë (thirrja sistemore
load)në memorie dhe ta ekzekutojë (execute) ndonjë program tjetër. Këto thirrje programore i
mundësojnë një programi ta vendosë në memorie dhe ta startojë ndonjë program tjetër. Se çka
duhet bërë me të përfunduar të punës së programit të thirrur, gjegjësisht, kujt duhet dorëzuar
kontrollin mbi kompjuter, do të varet nga ajo se çka ka ndodhë me programin i cili e ka inicuar
ekzekutimin e një programi tjetër, pra nga ajo se a është humbur ai program, a është ndaluar
përkohësiaht, apo është ekzekutuar paralelisht me programin ekzekutimin e të cilit e ka inicuar.
Nëse me të përfunduar të programit të thirrur kontrolli i dorëzohet programit thirrës,
shtrohet nevoja e ruajtjes së gjendjes së tij para momentit të fillimit të ekzekutimit të programit të
thirrur. Kjo nënkupton se në sistem operativ duhet krijuar mekanizmin që mundëson thirrjen e një
programi nga ndonjë program tjetër. Nëse ty dy programet do të vazhdojnë punën paralelisht, kjo
do të thotë se në sistem është krijuar një proces ose punë e re. Thirrja sistemore për krijimin e
procesit të ri quhet të shumtën e rasteve create process (shq. krijo procesin) ose submit job
(shq. dorëzoje procesin).
Gjatë punës, ekziston nevoja që të përcjellet rrjedha dhe gjendja e proceseve të krijuara,
pra të lexohen ose të vendosen atributet e procesit. Për këtë ekzistojnë dy thirrje sistemore, njëra
për leximin e atributeve të procesit, get process attributes dhe tjetra për vendosjen e atributeve
të procesit set process attributes. Për përfundimin e procesit përdorim thirrjen sistemore
terminate process.
Ndonjëherë do të paraqitet nevoja që proceset të presin që të kalojë ndonjë interval kohor
për vazhdimin e punës së tyre, me ç'rast përdoret thirrja sistemore wait time. Ndonjëherë procesi
do të duhet të pret ndonjë ngjarje, me ç'rast pritja do të inicohet me thirrjen sistemore wait event.
Kur të ketë ndodhur ngjarja e pritur procesi duhet të sinjalizojë sistemin operativ (thirrja siste­
more signal event).
Për korigjimin e gabimeve të programit përdoret shpesh thirrja programore dump, me të
cilën fitojmë përmbajtjen e memories dhe thirrja sistemore trace me të cilën mundësohet përcjellja
e ekzekutimit të programit dhe gjendja e regjistrave dhe memories pas secilit instruksion.

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

Datotekat mund të trajtohen si njësi abstrakte ose virtuale. Mund të konkludojmë se


shumë thirrje programore të nevojshme për manipulim me datoteka janë të nevojshme edhe për
kontrollin e punës së njësive kompjuterike.
Nëse në sistem ka më shumë shfrytëzues, njësinë që dëshirojmë ta përdorim, duhet ta
kërkojmë (thirrja sistemore request) nga sistemi operativ dhe pasi ta kemi kryer punën me të ta
lirojmë (thirrja sistemore release) që të mund ta shfrytëzojnë të tjerët. Këto thirrje janë analoge
me thirrjet sistemore open dhe close.
Nga njësia e dhënë mund të lexojmë (read) të dhënat, të shkruajmë (write) dhe të
pozicionohemi në vend të caktuar (reposition).
Për shkak se ekziston një ngjashmëri e madhe mes operacioneve që kryhen mbi datoteka
dhe operacioneve që kryhen mbi njësi të sistemit kompjuterik, shumë sisteme operative sistemin e
datotekave dhe sistemin e njësive hyrëse-dalëse e trajtojnë si një sistem. Në sistemet e tilla
operative njësitë hyrëse-dalëse të sistemit kompjuterik trajtohen si datoteka speciale.

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.

2.2.2 Implementimi i thirrjeve sistemore

Thirrjet sistemore paraqiten në mënyra të ndryshme varësisht nga kompjuteri që përdoret.


Ka kompjuterë që kanë instruksionin që shkakton trep dhe ia bartë kontrollin direkt sistemit
operativ. Zakonisht në këtë rast 8 bitët më pak të rëndësishëm tregojnë numrin identifikues të
thirrjes sistemore. Por, ka edhe kompjuterë që nuk e kanë instruksionin e thirrjes sistemore. Te
këto raste, siç është bie fjala mikroprocesori Intel 8080 me sistemin operativ CP/M thirrja
sistemore realizohet me vendosjen e numrit të funksionit në regjistrin C dhe kërcim në lokacionin
5 në memorie.
Sidoqoftë, gjithmonë është e nevojshme që të tregohet se për cilën thirrje sistemore është
fjala. Zakonisht duhet dhënë edhe disa informata tjera plotësuese, për shembull, emrin e njësisë
nga e cila do të lexohet ndonjë informatë, adresën dhe madhësinë e bufferit të saj sistemor etj.
Disa nga këto të dhëna mund të jenë të nënkuptuara. Tipi i saktë dhe sasia e informatave të
kërkuara do të varet nga thirrja sistemore dhe sistemi operativ i kompjuterit konkret.

19
Fig.2.1 Bartja e parametrave si tabelë

Për bartjen e parametrave të thirrjes sistemore përdoren zakonisht regjistrat e njësisë


qendrore. Nëse ka më shumë parametra se regjistra, atëherë mund të shfrytëzohet blloku ose
tabela e vendosur në memorien operative. Në këtë rast adresa e blloku jepet si parametër në
regjistër.
Thirrjet sistemore janë në dispozicion si instruksione asemblerike. Disa sisteme operative
mundësojnë që thirrja sistemore të jepet edhe si instruksion i gjuhës më të lartë programore, me
ç'rast ekzekutohet një nënprogram ose funksion i definuar më parë.
Ekzistojnë gjuhë të larta programore, siç është për shembull gjuha programore C, që
mundëson që thirrja sistemore të bëhet direkt. Një qëllim i koncipimit të gjuhëve të tilla ka qenë
që të zëvendsojnë asemblerin në problemet e programimit sistemor.

2.2.3 Programet sistemore

Sistemet moderne operative përmbajnë edhe kolekcionin e programeve sistemore. Këto


programe shërbejnë për zgjidhjen e problemeve të njejta apo të ngjashme të shumicës së
shfrytëzuesve dhe aplikacioneve. Ato ofrojnë rrethinë më të përshtatshme për zhvillimin dhe
ekzekutimin e programeve.
Programet sistemore mund t'i përkasin disa kategorive.
Manipulimi me datoteka. Këto programe krijojnë, fshijnë, kopjojnë, riemrojnë, shtypin,
listojnë dhe në përgjithësi kryejnë manipulimet e nevojshme me datoteka dhe direktoriume.
Informatat për statusin. Programet sistemore munden të gjenerojnë të dhëna që ofrojnë
informata për orën, datën, sasinë e memories së lirë, etj.
Modifikimi i datotekave. Për modifikimin e përmbajtjes së datotekave përdoren tekst
editorët. Ky lloj i programeve mund të gjinden dhe të blihen edhe ndamas nga sistemi operativ.
Përkrahja programimit në gjuhë të larta. Për gjuhët programore shpesh së bashku me
sistemin operativ vijnë edhe kompajlerët, interpreterët dhe asemblerët. Këto programe mund

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

do të shkaktojë që komand interpreteri ta kërkojë datotekën delete që përmbanë të gjitha


informatat e nevojshme për kryerjen e operacionit të fshirjes. Në këtë mënyrë, komandat e reja
mund t'i shtohen lehtë sistemit operativ, thjeshtë duke e shkruar kodin e nevojshëm për to.
Komand interpreteri në këtë rast nuk do të ketë nevojë të modifikohet. Me rëndësi është edhe që
hapësira që do të zë në memorie do të jetë dukshëm më e vogël.
Problemi që është i lidhur me këtë çasje të realizimit të komand interpreterit është bartja e
parametrave. Pasi komand interpreteri inicon ekzekutimin e programit sistemor që kryen
operacionin e dëshiruar, duhet siguruar mekanizmi i bartjes së parametrave të komandës, të
lexuara nga komand interpreteri, programit aktual sistemor.

2.3 Këndvështrimi i sistemit operativ

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.

2.3.1 Thirrjet sistemore

Thirrjet sistemore klasifikohen në bazë të llojit të thirrjes. Secila thirrje sistemore e ka në


kuadër të sistemit operativ kodin që përshkruan aksionin që duhet kryer. Do të shqyrtojmë:
Përfundimi normal. Nëse është dhënë thirrja sistemore për përfundimin normal të
programit, sistemi operativ duhet dorëzuar kontrollin komand interpreterit. Komand interpreteri
më pastaj e lexon komandën e ardhshme.
Përfundimi jonormal. Programi i cili vendos se duhet të përfundojë ekzekutimin e vet
në mënyrë jonormale, mund të kërkojë që të shikohet përmbajtja e memories dhe të paraqitet
porosia për gabimin. Hapi i ardhshëm do të jetë thirrja e komand interpreterit. Në sistemin
interaktiv komand interpreteri do të vazhdojë me komandën e ardhshme. Supozohet se
shfrytëzuesi do të jep komandën e nevojshme si përgjegje në gabim. Në beç sistem komand
interpreteri do ta ndërprejë krejt punën dhe do ta startojë ndonjë punë tjetër.
Kërkesat për status. Një klasë e thirrjeve sistemore kërkon nga sistemi operativ që të jep
disa informata. Këto janë zako-nisht informatat për orën, datën, atributet e punëve dhe datoteka­
ve, madhësinë e memories së lirë, gjendjen e njësive të ndryshme, etj. Pasi të jetë llogaritur
informata e kërkuar, kontrolli i dorëzohet programit që ekzekutohet.
Kërkesat për resurse. Gjatë ekzekutimit të vet programi mund të kërkojë më shumë
resurse të kompjuterit me qëllim të vazhdimit të punës. Këtu është fjala për më shumë memorie,
njësi të disqeve ose shiritëve, etj. Nëse resurset janë në dispozicion, sistemi operativ do t'ia jep
këto resurse programit që i ka kërkuar dhe do t'ia kthej kontrollin mbi kompjuter, përndryshe
programi do të presë derisa resursi të jetë në dispozicion.
Kërkesat për hyrje-dalje. Numri më i madh i kërkesave të programeve që ekzekutohen
do të jenë për kryerjen e operacioneve të hyrje-daljes me datoteka dhe njësi hyrëse-dalëse.

2.3.2 Ndërprerjet e njësive hyrëse-dalëse

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:

Loop: jmp Loop

që nuk do të përfundojë deri në momentin e paraqitjes së ndërprerjes.


Përparësi e pritjes në përfundimin e hyrje-daljes është se gjithmonë mund të ekzistojë më
së shumti një kërkesë e paraqitur për hyrje-dalje. Në këtë mënyrë në momentin e ndërprerjes
sistemi operativ e di se cila njësi e ka shkaktuar. Mirëpo, pritja në përfundimin e hyrje-daljes
pamundëson kryerjen simultane të më shumë operacioneve të hyrje-daljes.

Fig.2.2 Tabela e gjendjes së njësive

Fillimi i hyrje-daljes dhe kthimi i menjëhershëm i kontrollit mbi kompjuter programit të


shfrytëzuesit është zgjidhje që kërkon nga sistemi operativ që të mirëmbajë tabelën e gjendjes së
njësive. Çdo hyrje në këtë tabelë tregon tipin e njësisë, adresën dhe gjendjen e saj (e zënë, e lirë
ose nuk funksionon). Nëse njësia është e zënë me ndonjë kërkesë, atëherë lloji i kërkesës, dhe
parametrat tjerë do të vendosen në vendin e njësisë në tabelë. Pasi është e mundur që i njejti
program të paraqet më shumë kërkesa për të njejtën njësi, mund të kemi listën e kërkesave që
presin. Pra, sistemi operativ përveç listës së njësive hyrëse-dalëse mund të përmbajë listën e
kërkesave për secilën njësi. Me ndihmën e këtyre dy listave ai mirëmban evidencën e kërkesave të
parashtruara dhe kontrollon gjendjen e njësive të kërkuara për kryerjen e operacionit të hyrje-
daljes.
Njësia hyrëse-dalëse do të shkaktojë ndërprerje kur ka nevojë të shërbehet. Me paraqitjen
e ndërprerjes së pari përcaktojmë njësinë që e ka shkaktuar. Pastaj, e shikojmë tabelën e gjendjeve
të njësivë hyrëse-dalëse për të përcaktuar gjendjen momentale të saj dhe e modifikojmë
përmbajtjen e saj në mënyrë që të tregojmë paraqitjen e ndërprerjes. Për shumicën e njësive,

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.

2.3.3 Gabimet e programit

Gabimet e programit shkatojnë llojin e tretë të ndërprerjeve. Disa lloje të gabimeve të


programit, siç janë për shembull tentimi për ekzekutimin e instruksionit të privilegjuar,
instruksioni ilegal, ose tentimi që ti qasemi lokacionit memorik të palejuar, shkaktojnë trep
hardverik. Trepi, përmes vektorit të ndërprerjes do t'ia bartë kontrollin sistemit operativ në të
njejtën mënyrë si ndërprerja e gjeneruar nga ndonjë njësi.
Secilën herë që të parqitet gabimi i programit, sistemi operativ duhet të përfundojë në
mënyrë jonormale ekzekutimin e programit. Kjo situatë do të trajtohet njëlloj si kërkesa për
ndërprerje jonormale e dhënë nga shfrytëzuesi.

2.3.4 Rrjedha e përgjithshme

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

Për shumicën e shfrytëzuesve sistemi i datotekave është pjesa më e dukshme e sistemit


operativ. Në fillim të themi vetëm se datotekat ruajnë të dhëna dhe programe.

3.1 Koncepti i datotekës

Puna me datoteka është siç e përmendëm më lartë, puna më e shpeshtë që shfrytëzuesi e


bënë duke shfrytëzuar shërbimet e sistemit operativ. Kompjuteri mund t'i ruajë të dhënat në njësi
me karakteristika të ndryshme fizike dhe organizative, më të përdorurat nga të cilat janë disqet
dhe shiritat magnetik.
Që përdorimin e kompjuterit ta bëjë më të përshtatshëm sistemi operativ ofron trajtim
uniform logjik të hapësirës së paraparë për ruajtjen e të dhënave. Këtë ai e bënë duke definuar
njësinë logjike për ruajtjen e të dhënave - datotekën. Me ndihmën e sistemit operativ datotekat
mapohen në njësitë konkrete fizike ku do të ruhen.
Datoteka është varg i të dhënave që kanë lidhje mes veti të definuar nga krijuesi i
datotekës. Mund të përdorim definicion edhe më të thjeshtë e të themi se datoteka është varg i
bajtëve. Zakonisht datotekat paraqesin programe (burimore ose ekzekutive) dhe të dhëna. Të
dhënat në datotekë mund të jenë numerike, alfabetike ose alfanumerike. Datotekat mund të kenë
të dhëna në formë të lirë ose të formatizuar.
Datotekës i qasemi përmes emrit. Datoteka mund të ketë edhe të dhëna të tjera si tipin,
madhësinë, kohën e krijimit etj.

3.1.1 Tipet 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.

3.1.2 Sistemet e bazuara në shiritat magnetik

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

3.1.3 Sistemet e bazuara ne disqe

Problemet e përmendura me shiritë janë zgjedhur me paraqitjen e disqeve. Sipërfaqja e


diskut është e ndarë në treka. Çdo trek është i ndarë në sektorë. Numri i trekëve dhe sektorëve në
trek varet nga kapaciteti i diskut. Njësia më e vogël nga e cila mund të lexohet ose në të cliën
mund të shkruhet informata është sektori. Varësisht nga disku madhësia e sektorit mund të jetë
prej 32 deri 4096 bajtë. Sistemet e mëdha të disqeve mund të kenë më shumë disqe të lidhur në
një bosht. Çdo disk i tillë ka dy sipërfaqe punuese. Për të definuar pozicionin e një sektorit duhet
përcaktuar sipërfaqen, trekun dhe sektorin. Koha e nevojshme që koka të vendoset mbi trekun e
kërkuar është koha e kërkimit (ang. seek time). Më pas, duhet pritur që sektori i dëshiruar të
mbërrijë nën kokë. Koha e tillë quhet kohë e vonesës ose pritjes (ang. latency time). Trekat e
njejtë në sipërfaqe të ndryshme përbëjnë cilindrin. Qasja e trekëve në cilindër të njejtë nuk kërkon
kërkimin e tyre.

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.

Fig.3.2 Mapimi i datotekave logjike në njësi fizike

Operacionet minimale që do të kryejmë mbi datoteka do të jenë: krijimi i datotekës,


shkruarja në datotekë, pozicionimi në kuadër të datotekës, leximi nga datoteka dhe fshirja e
datotekës. Operacionet e tjera të dëshirueshme do të ishin: editimi (modifikimi) i përmbajtjes së
datotekës, shtimi i informatave të reja datotekës ekzistuese, kopjimi i datotekës dhe riemërimi i
saj.

3.2 Përkrahja punës me 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.

3.2.1 Operacionet me datoteka

Do të supozojmë se sistemi i datotekave është i bazuar në disk. Të shofim se çka bëjnë


këto 5 operacione bazike.
Krijimi i datotekës. Për krijimin e datotekës janë të nevojshmë dy hapa. Së pari duhet
gjetur hapësira e lirë në njësi, e pastaj duhet që në direktorium të shtohet një hyrje e re që do të
përmbajë emrin e datotekës dhe lokacionin e saj në sistemin e datotekave.

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.

3.2.2 Direktoriumi i njësisë

Se cilat informata do të ruhen në direktorium varet nga sistemi operativ. Në shumicën e


sistemeve ruhen këto të dhëna:
Emri i datotekës që paraqet emrin simbolik të datotekës.
Tipi i datotekës në sistemet që përkrahin tipet e ndryshme të datotekave.
Lokacioni. Fjala është për treguesin në njësinë dhe pozitën e datotekës në njësi.
Madhësia momentale e datotekës në bajtë, fjalë ose blloqe dhe madhësia maksimale e
lejuar.

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.

3.3 Metodat e qasjes

Ekzistojnë disa mënyra të qasjes informatave që ndodhen në datoteka. Ka sisteme që


lejojnë vetëm një mënyrë të qasjes datotekave dhe sisteme ku përkrahen disa mënyra të qasjes të
dhënave në datotekë. Zgjedhja e mënyrës së qasjes të dhënave është problem që i lihet në
përgjegjësi programerit të aplikacionit dhe paraqet problem jo të zakonshëm.

3.3.1 Qasja sekuenciale

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.

Fig.3.3 Datoteka me qasje sekuenciale

3.3.2 Qasja direkte

Qasja direkte është metodë alternative e bazuar në modelin e datotekës së vendosur në


disk. Për qasje direkte datoteka trajtohet si sekuencë e numëruar e blloqeve ose rekordeve.
Blloku është zakonisht me gjatësi fikse dhe është i definuar nga sistemi operativ si njësi minimale
pozicionuese.

Fig.3.4 Datoteka me qasje direkte

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.

3.3.3 Mënyrat tjera të qasjes

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.

Fig.3.5 Struktura e datotekave për ISAM

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).

3.4 Metodat e vendosjes

Implementimi i datotekës është problem i sistemit operativ.


Në sistemet e bazuara në shirita magnetik implementimi është relativisht i thjeshtë, falë
kufizimeve të punës me shirit. Mund të mapojmë një datotekë në një shirit ose të mapojmë më
shumë datoteka në një shirit. Qasja sekuenciale është e vetmja mënyrë e qasjes që ka kuptim.
Për datoteka në disk mund të kemi më shumë liri në implementimin e tyre. Pasi në të
shumtën e rasteve do të kemi më shumë datoteka në një disk, problem kryesorë do të jetë se si
datotekave të tilla t'ua ndajmë hapësirën ekzistuese në mënyrë që kjo hapësirë memorike të
shfrytëzohet efektivisht, e datotekave të mund t'iu qasemi shpejt. Për ndarjen e hapësirës
memorike shfrytëzohen tri mënyra kryesore: e pandërprerë, e lidhur dhe e indeksuar. Ka sisteme
operative që përkrahim të tri mënyrat por shumica shfrytëzon vetëm njërën nga këto.

3.4.1 Udhëheqja me hapësirën e lirë

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ë.

Fig.3.6 Lista e lidhur e hapësirë së lirë në disk

Për shkak të numrit të madh të operacioneve hyrëse-dalëse të nevojshme ky princip mund


të modifikohet ashtu që në bllokun e parë të lirë do të shkruheshin adresat e n blloqeve të lira. Në
fakt, vetëm n-1 blloqet e tilla janë me të vërtetë të lira. I fundit paraqet adresën e bllokut tjetër që
përmban adresat e n blloqeve tjera të lira.
Një qasje tjetër këtij problemi shfrytëzon vetinë që në përgjithësi blloqe të mëdha të
pandërprera lirohen apo zihen njëkohësisht, posaçërisht në rastet kur përdoret vendosja e
pandërprerë. Në këtë rast, në vend se të ruajmë adresat e blloqeve të lira, do të ruajmë adresën e
bllokut të lirë dhe numrin e blloqeve të lira që e përcjellin. Çdo hyrje në listën e hapësirës së lirë
përbëhet nga adresa e bllokut dhe numri. Edhepse secila hyrje e veçantë në listë zë më shumë
vend e tërë lista është më e shkurtër derisa në shumicën e hyrjeve numri që shoqëron adresën e
bllokut është më i madh se 1.

3.4.2 Vendosja e pandërprerë

Vendosja e pandërprerë kërkon që çdo datotekë të zë adresa të njëpasnjëshme në disk.

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.

Fig.3.7 Vendosja e pandërprerë

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.

Shpërndarja dinamike e hapësirës memorike

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ë).

Problemet me vendosjen e pandërprerë

Problemi kryesor me vendosjen e datotekave në hapësirë të pandërprerë memorike është


caktimi i hapësirës së nevojshme për datotekë. Nëse është fjala për kopjimin e datotekës ky
problem nuk është edhe aq i shprehur, por çka do të ndodhë nëse kur e kemi krijuar datotekën ia
kemi ndarë, ta zëmë, hapësirën n bllokëshe, e më kohë për shkak të natyrës së aplikacionit
datoteka duhet të rritet.
Ky problem është i shprehur posaçërisht nëse është zbatuar strategjia e dhënjë së
hapësirës që më së miri i përgjigjet kërkesës. Është gjasa shumë e madhe që hapësira para dhe pas
datotekës të jetë e shfrytëzuar. Problemi mund të zgjidhet ashtu që programi të ndërprehet, e
datotekës ti rezervohet më shumë vend. Këto ndërprerje të programit ndoshta do të duhet të
përsëriten disa herë. Në këso raste, programeri zakonisht ia ndanë paraprakisht datotekës
hapësirën më të madhe, që ka si rezultat shfrytëzimin joefektiv të hapësirës në disk.
Ky problem mund të zgjidhet edhe duke e kopjuar datotekën në një vrimë më të madhe,

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.

3.4.3 Vendosja e lidhur

Problemet e përmendura më lartë e kanë burimin në mënyrën e vendosjes së datotekave


në hapësirë të pandërprerë. Ky problem zgjidhet me vendosje të lidhur. Te kjo mënyrë e
vendosjes datoteka paraqet listë të lidhur të blloqeve të diskut. Blloqet mund të jenë të vendosur
kudo në disk. Direktoriumi përmban treguesin në bllokun e parë (dhe të fundit) të datotekës.
Blloku i parë përmban treguesin në bllokun e dytë e kështu me rradhë deri te blloku i fundit.
Shfrytëzuesi nuk është në gjendje të ndërrojë përmbajtjen e këtyre treguesve. Nëse për këtë
tregues na nevojiten dy bajta atëherë shfrytëzuesi do ta identifikojë bllokun 512 bajtësh si 510
bajtësh. Krijimi i datotekave është i lehtë. Në direktorium shtohet emri i datotekës, e treguesi i
bllokut të parë inicializohet në 0, për të treguar se datoteka është e zbrazët. Kur të shkruajmë në
datotekë e marrim bllokun e parë të lirë nga lista e blloqeve të lira dhe shkruajmë në te. Ky bllok
pastaj lidhet për fundin e datotekës. Kur e lexojmë datotekën sistemi operativ kalon prej një
blloku në tjetrin duke përcjellë treguesit prej një blloku në tjetrin.
Me vendosje të lidhur nuk do të kemi fragmentim të jashtëm. Cilido bllok nga lista e
blloqeve të lira mund të përdoret për arsye se blloqet janë të lidhura së bashku. Poashtu gjatë
krijimit të datotekës nuk është e nevojshme të paracaktohet madhësia e datotekës. Datoteka
mund të rritet derisa ka vend të lirë në disk. Kompaktëzimi nuk është i nevojshëm.
Dobësi e vendosjes së lidhur është se ajo efektivisht mund të përdoret vetëm për qasje
sekuenciale datotekave. Për gjetjen e bllokut të i-të duhet të nisemi nga blloku i parë e pastaj të
përcjellim treguesit deri te blloku i dëshiruar. Çdo qasje treguesve nënkupton lexim të diskut.
Rrjedhimisht nuk mund të përkrahet qasja direkte me datoteka të vendosura në blloqe të lidhura.

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.

3.4.4 Vendosja e indeksuar

Vendosja e lidhur i ka zgjedhë problemet në lidhje me fragmentimin ekstern të hapësirës


së diskut dhe problemet në lidhje me nevojën e deklarimit paraprak të madhësisë së datotekës.
Mirëpo, pasi blloqet e një datoteke janë të shpërndarë nëpër tërë hapësirën e diskut kjo mënyrë e
vendosjes nuk mund të përkrahë qasjen direkte. Përveç blloqeve edhe treguesit në blloqe janë të
shpërndarë nëpër tërë hapësirën e diskut. Këtë problem e zgjedh vendosja e indeksuar e cila
treguesit në blloqe i vendos në një vend - në indeks bllok.

40
Fig.3.9 Vendosja e indeksuar

Çdo datotekë e ka indeks bllokun e vet, që paraqet fushë të adresave të blloqeve.


Elementi i i-të në indeks bllok tregon në bllokun e i-të të datotekës. Direktoriumi përmban
adresën e indeks bllokut. Për ta lexuar bllokun e i-të, do ta shfrytëzojmë elementin e i-të të indeks
bllokut, përmbajtja e të cilit na shërben ta gjejmë dhe ta lexojmë bllokun e dëshiruar. Në
momentin e krijimit të datotekës të gjithë treguesit në indeks bllok inicializohen në vlerën zero.
Kur për të parën herë shkruajmë në bllokun i, blloku i do të hiqet nga lista e blloqeve të lira,
ndërsa adresa e tij do të vendoset në elementin e i-të të indeks bllokut.
Vendosja e indeksuar mundëson qasjen direkte dhe eliminon copëzimin e jashtëm.
Kërkesën për më shumë hapësirë mund ta kënaq cilido bllok kudo në disk.
Mirëpo edhe këtu kemi shfrytëzim joracional të hapësirës. Për çdo datotekë është e
domosdoshme prania e indeks bllokut. Nëse datoteka është e vogël, ta zëmë se okupon një ose
dy blloqe, atëherë sikur të përdorej vendosja e lidhur do të kishim një ose dy tregues, pra do të
kishim të zënë dy ose katër bajta (nëse treguesit janë të gjatësisë dy bajtë). Për datotekë të njejtë
të vendosur në mënyrë të indeksuar do të kishim në indeks bllok vetëm një ose dy tregues të
ndryshëm prej zeros. E tërë hapësira tjetër e indeks bllokut do të shpenzohej kot.
Kjo na shtyn të mendojmë se sa duhet të jetë madhësia e indeks bllokut. Pasi çdo datotekë
duhet ta ketë indeks bllokun e datoteka mund të ketë shumë, do të tentojmë që madhësia e indeks
bllokut të jetë sa më e vogël. Por, nëse indeks blloku është shumë i vogël, ai nuk do të jetë në
gjendje të ruajë numër të mjaftueshëm të treguesve për datotekë më të madhe. Indeks blloku
zakonisht shfrytëzon një bllok dhe mund të lexohet dhe shkruhet vetëvetiu (nënkupton pa

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.

3.5 Sistemet e direktoriumeve

Datotekat janë të përfaqësuara me hyrje (elemente) në direktoriumin e njësisë ose tabelën


e përmbajtjes së vëllimit (ang. Volume Table Of Contents, VTOC, notacion i IBM-së).
Direktoriumi i njësisë ruan të dhëna për emrin, tipin, madhësinë e datotekës dhe të dhëna të tjera.
Direktoriumi i njësisë do të mjaftonte në sistemin me një shfrytëzues (ang. single user
system), me hapësirë të kufizuar memorike. Me rritjen e hapësirës memorike dhe numrit të
shfrytëzuesve vështirësohet përcjellja e përmbajtjeve të ndryshme në disk. Problemi zgjidhet me
aplikimin e strukturës së direktoriumeve mbi sistemin e datotekave. Struktura e direktoriumeve
mund të kapërcëje kufijtë e njërës njësi dhe të përfshijë më shumë njësi të disqeve. Në këtë
mënyrë shfrytëzuesi mundet, nëse dëshiron, të merr në konsiderim vetëm strukturën logjike të
direktoriumeve dhe datotekave dhe plotësisht të injorojë shpër-ndarjen fizike të datotekave nëpër
disqe ose njësi tjera.
Shumë sisteme kanë dy struktura të direktoriumeve: direktoriumet e njësive dhe
direktoriumet e datotekave. Direktoriumi i njësisë është i vendosur në njësi dhe përshkruan të
gjitha dato- tekat që ndodhen në atë njësi. Direktoriumi i njësisë kryesisht ndalet në përshkrimin
fizik të datotekës: ku ndodhet, sa është e gjatë, si është e vendosur etj. Direktoriumi i datotekave
tregon organizimin logjik të datotekave në të gjitha njësitë. Ai jep më shumë informata logjike për
datotekën, emrin, tipin, pronarin, kodet për kufizimin e qasjes e të ngjashme. Një hyrje në
direktoriumin e datotekave mund ta ketë kopjen e të dhënave për datotekën gjegjëse nga
direktoriumi i njësisë, ose mund ta ketë vetëm treguesin në këto të dhëna që ndodhen në
direktoriumin e njësisë.
Ekzistojnë struktura të ndryshme të direktoriumeve. Dire-ktoriumi është në esencë tabelë
simbolike. Do të përmendim ope-racionet që duhet të kryhen mbi direktorium.
Kërkimi. Shfrytëzuesi duhet të jetë në gjendje të kërkojë strukturën e direktoriumit për të
gjetë të dhënat për datotekën e dëshiruar. Pasi emrat e datotekave janë emra simbolik, e emrat e
ngjashëm mund të tregojnë lidhje mes datotekave, do të na interesonte që të kemi mundësi të

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.

3.5.1 Direktoriumet njënivelëshe

Direktoriumi njënivelësh është struktura më e thjeshtë e direktoriumeve. Direktoriumi i


njësisë mund të jetë shembull i direktoriumit të tillë. Të gjitha datotekat ndodhen në këtë
direktorium.

Fig.3.10 Direktoriumi njënivelësh

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

Që të eliminohet problemi i emrimit të datotekave në sis-temin me shumë shfrytëzues,


imponohet krijimi i direktoriumeve të veçanta për secilin prej tyre. Posaçërisht në sistemet e
mëdha direktoriumi paraqet më shumë strukturë logjike se sa fizike pasiqë të gjitha datotekat
mund të ndodhen edhe ashtu në një njësi.
Në direktoriumin dynivelësh shfrytëzuesi e ka direktoriumin e datotekave të shfrytëzuesit
(ang. User File Directory, UFD). Çdo shfrytëzues e ka strukturën e njejtë të direktoriumit
(lineare, binare ose hash strukturë) por ai direktorium përmban vetëm datotekat e atij
shfrytëzuesi. Kur shfrytëzuesi ti para-qitet sistemit me të filluar të punës, kërkohet direktoriumi
kryesor i datotekave (ang. Master File Directory, MFD). MFD është i indeksuar sipas emrit ose
numrit të shfrytëzuesit.

Fig.3.11 Struktura dynivelëshe e direktoriumit

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).

3.5.3 Direktoriumet me strukturë të pemës

Gjeneralizim i direktoriumit dynivelësh është struktura e direktoriumit në formë të pemës.


Te kjo strukturë shfrytëzuesve u është lejuar që vetë të krijojnë nëndirektoriumet e veta dhe ti
organizojë datotekat sipas dëshirës. Sistemi i datotekave të shumë sistemeve operative është i
strukturuar si pemë. Pema e ka direktoriumin rrënjë. Në këtë lloj të organizimit çdo datotekë e ka
emrin unik të shtegut. Emri i shtegut paraqet shtegun që shkon prej rrënjë nëpër të gjitha
nëndirektoriumet deri te dato-teka e specifikuar.
Te ky organizim, direktoriumi përmban datoteka dhe nëndirektoriume. Secili
nëndirektorium e ka formatin e njejtë intern. Për të treguar se a është fjala për datotekë apo për
direktorium përdoret një bit.
Shfrytëzuesit e kanë direktoriumin e tyre punues, në të cilin i vendosin datotekat më të
rëndësishme. Kur dëshirojmë ti qasemi një datoteke, sistemi do ta kërkojë në këtë direktorium.
Nëse nuk e gjenë aty, atëherë mundemi nëse ende dëshirojmë ti qasemi, ta specifikojmë shtegun
deri te datoteka e dëshiruar ose të kalojmë në direktoriumin ku ndodhet ajo datotekë. Në rastin e
dytë thirrja sistemore do ta merr emrin e direktoriumit si parametër dhe do ta shfrytëzojë atë për
të definuar direktoriumin e ri punues. Shfrytëzuesit mund ta ndërrojnë direktoriumin e tyre
punues sa herë të dëshirojnë.
Emri i shtegut mund të jetë emër komplet dhe relativ. Emri komplet fillon nga rrënja dhe
vazhdon duke përfshirë të gjitha emrat e nëndirektoriumeve deri te datoteka e dëshiruar. Emri
relativ i shtegut fillon nga direktoriumi punues duke përfshirë emrat e nëndirektoriumeve prej
direktoriumit punues deri te datoteka. Nëse direktorium punues është direktoriumi /shfra/gjuhët,
atëherë shtegu relativ /fortran/prg1 i referohet të njëjtës datotekë të dhënë me shtegun e saj
komplet /shfra/gjuhët/fortran/prg1.

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ë.

Fig.3.12 Struktura e direktoriumit me strukturë të pemës

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.

3.5.4 Direktoriumet me strukturë të grafik aciklik

Të marrim rastin kur dy programerë punojnë në të njejtin projekt. Datotekat e këtij

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.

Fig.3.13 Struktura direktoriumit në formë të grafit aciklik

Struktura e pemës nuk lejon ekzistimin e direktoriumeve dhe datotekave të përbashkëta.


Grafi aciklik që paraqet gjeneralizim të strukturës së direktoriumit në formë të pemës, lejon që e
njejta datotekë ose nëndirektorium të ndodhet në dy direktoriume.
Direktoriumet e përbashkëta përdoren për të futur në to datotekat që shfrytëzohen në
mënyrë të barabartë nga më shumë shfrytëzues. Por edhe në rastin e sistemit me një shfrytëzues
është ndoshta e dëshirueshme që disa datoteka të ndodhen në dy ose më shumë direktoriume (e
njejta datotekë, jo kopja e saj).
Implementimi i datotekave dhe direktoriumeve të përbashkëta mund të realizohet përmes
krijimit të elemntit të ri në direktorium të quajtur lidhëse (ang. link). Lidhësja në fakt paraqet
tregues në një datotekë tjetër ose direktorium. Lidhësja mund të implementohet si emër komplet i
shtegut (lidhëse simbolike). Kur ti referohemi datotekës, së pari do të kërkohet direktoriumi dhe
aty do të gjendet elementi që plotëson kushtin dhe i cili është i markuar si lidhëse. Përmbajtja e

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.

3.5.5 Grafi i përgjithshëm i direktoriumit

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.

Fig.3.14 Direktoriumi me graf të përgjithshëm

Përdorimi i grafeve aciklike për përshkrimin e strukturës së direktoriumeve është i


preferueshëm për shkak të thjeshtësisë së algoritmit për realizimin e tij dhe mundësisë së
përcaktimit se a ka refrenca të bëra një datoteke ose direktoriumi. Sigurisht se shfrytëzuesi për
shkak të shpejtësisë së punës nuk do të dëshironte që e njejta komponentë e strukturës së direkto­
riumit të kërkohet dy herë nëse një kërkim veç ka dhënë rezultat negativ.
Edhe nëse ciklet do të jenë të lejuar, ne përsëri do të dëshironim që kërkimi të mos bëhet
më shumë herë se që është nevoja. Mirëpo, algoritmi i projektuar keq mund të na bjen në unazë të
pafundshme për shkak të mundësisë që një komponentë e direktoriumit ti referohet vetvehtes. Që
situata të lehtësohet ekzistojnë programe që kontrollojnë kur është fshirë referenca e fundit dhe e
lirojnë hapësirën e zënë nga datoteka referencat ekzistuese të së cilës janë fshirë.
Pasi që është shumë më lehtë të punohet me strukturë aciklike të direktoriumit sistemet
operative që përdorin këtë strukturë kanë programe sistemore speciale të cilat detektojnë
paraqitjen eventuale të cikleve dhe informojnë shfrytëzuesin. E gjithë kjo ka si rezultat
ngadalsimin e punës së kompjuterit.

3.6 Mbrojtja e datotekave

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.

3.6.3 Kontrolli i qasjes

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.

3.7 Problemet e implementimit

Projektimi i sistemit të datotekave mund të dahet në dy probleme të ndryshme. Problemi i


parë është se si do të duket ky sistem i shikuar nga ana e shfrytëzuesit. Këtu kemi të bëjmë me
definicionin e datotekës dhe atributeve të saj, operacionet e lejuara mbi datoteka dhe struktura e
direktoriumeve. Së fundit duhet krijuar algoritmet dhe strukturat e të dhënave që mundësojnë
pasqyrimin e sistemit logjik të datotekave në njësitë fizike që përdoren për vendosjen e të dhënave
të udhëhequra nga sistemi i datotekave.
Vetë sistemi i datotekave është i përbërë nga disa shtresa të ndryshme. Çdo shtresë
shfrytëzon mundësitë e shtresës së poshtme për të realizuar operacionet që do të shfrytëzohen
nga shtresat e epërme.
Niveli më i ultë i këtij sistemi shtresor, kontrolli i hyrje-daljes, përbëhet nga drajverët e
njësive (ang. device drivers) dhe programet për përpunimin e ndërprerjeve (ang. interrupt
handlers) që në fakt kontrollojnë transmetimin e të dhënave prej memories në disk dhe anasjelltas.
Sistemi themelor i datotekave (ang. Basic File System) i shfrytëzon këto për të shkruar ose lexuar
blloqet e veçanta nga disku dhe në disk. Çdo bllok i diskut është i identifikuar me adresën e vet
numerike (p.sh. diksku 1, cilindri 106, sipërfaqja 2 sektori 25).
Moduli i organizimit të datotekës (ang. File Organization Module) ka të njohur të dhënat
për datoteka dhe për blloqe. Duke njohur tipin e vendosjes së datotekës dhe pozitën e datotekës
ky modul gjeneron adresat e blloqeve që do të lexohen nga Sistemi themelor i datotekave. Së
fundit Sistemi logjik i datotekave e shfrytëzon strukturën e direktoriumeve për t'ia dhënë modulit
të organizimit të datotekave vlerat që i nevojiten.
Të shikojmë tani si funksionon kjo skemë duke u nisur nga aplikacioni i shfrytëzuesit. Për
të krijuar datotekën e re aplikacioni e thërret Sistemin logjik të datotekave. Ky sistem e njeh

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.

Fig.3.15 Sistemi shtresor i datotekave

Problem me përdorimin e tabelës së datotekave të hapura është rreziku i ndërprerjes së


pakontrolluar të punës së kompjuterit me ç'rast tabela e datotekave të hapura humbet (kjo tabelë
ruhet në memorien operative, përmbajtja e së cilës fshihet me ndërprerje të furnizimit), e
ndërrimet eventuale mbesin të papërcjella në direktoriumin e vendosur në disk. Sistemi i
datotekave në këtë rast mbetet në gjendje jokonzistente për arsye se të dhënat në direktorium nuk
i përgjigjen gjendjes aktuale në disk.
Në kuadër të problemeve të projektimit të sistemit operativ është kontrolli i qasjes. Çdo
qasje datotekës ose direktoriumit duhet të kontrollohet. Ka sisteme që kontrollojnë korektësinë e

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

Planifikimi i punës së njësisë qendrore (ang. CPU Scheduling), paraqet themelin e


sistemeve operative multiprogramore. Duke e bartur njësinë qendrore nga ekzekutimi i një
procesi në tjetrin, sistemi operativ rritë produktivitetin e tërë sistemit. Në vazhdim do të japim
disa koncepte themelore.

4.1 Koncepti i multiprogramimit

Koncepti më i rëndësishëm në teorinë e sistemeve operative është padyshim


multiprogramimi. Duke i mbajtur njëkohësisht më shumë procese në memorien operative,
mundemi që procesorin ta angazhojmë që alternativisht të ekzekutojë kodin e ndonjërit prej
proceseve të pranishme, duke shtuar në këtë mënyrë efikasitetin e përgjithshëm të sistemit
kompjuterik që arrihet me kryerjen e më shumë punëve për më pak kohë.

Fig.4.1 Dy punë, A dhe B për ekzekutim

Ideja e multiprogramimit është e thjeshtë. Një proces do të ekzekutohet deri në momentin


kur duhet të presë, në rastin tipik kryerjen e ndonjë kërkese për hyrje-dalje. Në sistemin e thjeshtë
kompjuterik nuk do të ndodhë asgjë; procesori do të pret që ky operacion të kryhet. Nëse kemi
multiprogramimin e zbatuar, kjo kohë nuk do të humbet, por do të shfrytëzohet racionalisht. Kur
një proces do të ketë nevojë të pret, sistemi operativ do t'ia "merr" procesorin dhe do t'ia "jep"
ndonjë procesi tjetër nga grupi i proceseve që ndodhen në atë moment në memorien operative.
Dhe kështu me rradhë. Sa herë që një proces ka nevojë të pret, një tjetër do të vazhdojë të
ekzekutohet.

Fig.4.2 Ekzekutimi i punëve pa multiprogramim

Përparësitë e multiprogramimit janë shfrytëzimi më i madh i procesorit dhe numri më i


madh i punëve të kryera për njësi të kohës (rendimenti, ang. throughput). Si shembull kufitar të
marrim se kemi dy punë A dhe B të cilat duhet të ekzekutohen. Të marrim se çdo punë

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.

Fig.4.3 Ekzekutimi i punëve me multiprogramim

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.

4.2 Konceptet e planifikimit kohor

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.

4.2.1 Komponentet themelore

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.

Ciklet procesor - hyrje/dalje

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ë

Fig.4.4 Histogrami i kohëzgjatjeve të breshërive të procesorit

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

Procesi është program në ekzekutim. Me ekzekutimin e programit, procesi ndërron


gjendjen. Gjendja e procesit është e definuar me aktivitetin e tij momental. Ekzekutimi i procesit
paraqesin sekuencat alternative të breshërive të procesorit dhe të hyrje-daljes që fillojnë dhe

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.

Fig.4.5 Diagrami i gjendjeve të procesit

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.

Fig.4.6 Diagrami i rafinuar i gjendjeve të procesit

Blloku kontrollues i procesit

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.

Fig.4.7 Blloku kontrollues i procesit

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

Objektiv i multiprogramimit është që në çdo moment të kemi proces i cili ekzekutohet,


me qëllim të maksimalizimit të shfrytëzimit të procesorit. Për sistemin me një procesorë nuk do të
kemi kur më shumë se një proces që ekzekutohet. Të tjerët do të duhet të presin. Proceset të cilët
janë të gatshëm dhe presin për tu ekzekutuar mbahen në listën e quajtur rresht i të gatshmëve
(ang. ready queue). Lista është në përgjithësi listë e lidhur. Çdo rresht e ka headerin (ang.
header, prej head që do të thotë kokë, header - diçka që është në krye) që përmban treguesin në
bllokun e parë dhe të fundit kontrollues të proceseve në list. Çdo bllok kontrollues i procesit
përmban fushën ku ndodhet treguesi në procesin e ardhshëm nga rreshti i proceseve të gatshme.
Rreshti i proceseve të gatshme mund të jetë i implementuar si FIFO rresht, si rresht
prioritar, si pemë, stek ose si listë e lidhur e parenditur. Sidoqoftë, të gjitha proceset në listë
presin që të fitojnë rastin të ekzekutohen.
Në sistem ekzistojnë edhe rreshta tjerë. Pasi të jetë ekzekutuar një kohë, procesi do të
përfundojë ose do të ndalet për shkak të kërkesës për ekzekutimin e hyrje-daljes. Kjo kërkesë
mund të jetë e drejtuar me qëllim të shfrytëzimit të një terminali ose njësie të diskut ose ndonjë

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.

Fig.4.9 Rreshti i proceseve të gatshme dhe rreshtat e njësive të ndryshme hyrëse-dalëse

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

Për të thjeshtuar diskutimin rreshtat e veçantë të njësive hyrëse dalëse do ti përmbledhim


me një rresht të njësisë dhe një njësi hyrëse-dalëse.

4.2.3 Planifikuesit

Sistemi operativ ka më shumë planifikues. Ekzistojnë dy planifikues kohor kryesor për


njësinë qendrore. Këta janë planifikuesi afatgjatë dhe afatshkurtër.

Fig.4.11 Diagrami i thjeshtuar i rreshtave

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ë.

Fig.4.12 Shtimi i planifikimit afatmesëm në diagramin e rreshtave

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 Algoritmet e planifikimit

Planifikimi i procesorit ka të bëjë me problemet e vendosjes se cilit nga proceset e


gatshme që presin në rresht, do ti jepet procesori. Ekzistojnë shumë algoritme të tilla.

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.

4.3.2 Algoritmi I-pari-që-vjen-i-pari-shërbehet

Algoritmi I-pari-që-vjen-i-pari-shërbehet (ang. First-Come-First-Served, FCFS) është


algoritmi më i thjesht. Te ky algoritëm procesi i parë që e kërkon procesorin do ta fitojë proceso­
rin. Implementimi i FCFS realizohet me FIFO rresht. Procesi që hyn në rreshtin e proceseve të
gatshme do të lidhet në fund të rreshtit. Kur procesori të jetë i lirë, do ti jepet procesit që është në
krye të rreshtit. Pas kësaj procesi që është ekzekutuar largohet nga rreshti.
Problem me këtë algoritëm është se zakonisht jep rezultate të dobëta. Të marrim se i kemi
tri punë për të cilat e dijmë se breshëria e ardhshme e procesorit do të zgjasë 24 njësi kohore, për
punën e parë, 3 njësi kohore për të dytën dhe 3 njësi për të tretën. Nëse punët arrijnë në sistem
sipas rradhës 1, 2, 3 dhe shërbehen sipas kësaj renditjeje, do të fitojmë diagramin vijues

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.

4.3.3 Algoritmi Së-pari-puna-më-e-shkurtë

Algoritmi Së-pari-puna-më-e-shkurtë (ang. Shortest Job First, SJF) ia bashkangjet secilës


punë kohëzgjatjen e breshërisë së ardhshme të procesorit. Kur procesori është i lirë ai do ti jepet
procesit që e ka breshërin e ardhshme më të shkurtë. Nëse dy punë e kanë të njejtën kohëzgjatje
të breshërisë së ardhshme të procesorit do të përdoret algoritmi FCFS.
Të marrin këtë shembull:
Puna Kohëzgjatja e breshërisë
1 6
2 3
3 8
4 7
Nëse përdorim algoritmin SJF renditja e punëve do të jetë: së pari puna 2, pastaj 1, 4 dhe 3.

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.

Fig.4.13 Vërtetimi i optimalitetit të algoritmit SJF

Problem me këtë algoritëm është pamundsia e njohjes së zgjatjes së breshërisë së


ardhshme. Derisa në punën e planifikuesit afatgjatë (planifikuesi i punëve) ky algoritëm mund të
përdoret duke u bazuar në disa supozime, siç është p.sh. definimi i limitit kohor të punës, te

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.

Fig.4.14 Parashikimi i breshërisë së ardhshme të procesorit me përdorimin e mesatares


eksponenciale

66
4.3.4 Prioriteti

Algoritmi Së-pari-puna-më-e-shkurtë është rast special i algoritmit të përgjithshëm me


prioritet. Prioriteti është i lidhur me secilën punë dhe punës me prioritet më të lartë i jepet
procesori. Punët me prioritet të njejtë trajtohen me algoritmin FCFS.
Algoritmi Së-pari-puna-më-e-shkurtë është algoritëm me prioritet ku prioriteti (p) është
është në proporcion të zhdrejtë me kohëzgjatjen e paraparë të breshërisë së ardhshme të
procesorit (τ), p=1/τ. Sa më e shkurtër breshëria më i lartë prioriteti dhe e kundërta.
Prioriteti mund të ketë disa nivele. Ai mund të jetë prej 0 deri 7 ose prej 0 dero 4095, ose
ndonjë brez tjetër. Zakonisht merret se prioritet më i lartë është prioriteti 0 edhepse ka sisteme ku
prioriteti më i lartë është i shprehur me numër më të madh, e ai më i ultë me numër më të vogël.
Prioritetet mund të definohen në mënyrë interne ose eksterne. Prioritetet interne varen
nga madhësitë e matshme. Fjala është për limitet kohore, kërkesat për memorie, numri i
datotekave të hapura dhe raporti i kohës së shpenzuar deri tani në kryerjen e operacioneve
hyrëse-dalëse dhe në kryerjen e llogaritjeve. Prioritetet e jashtme vendosen nga faktorë që janë të
jashtëm për sistemin operativ siç është p.sh. rëndësia e punës së kryer, sasia dhe burimet e të
hollave prej të cilave financohet shfrytëzimi i kompjuterit dhe nga faktorët tjerë që definojnë
politikën e shfrytëzimit të kompjuterit.
Problem kryesor me planifikimin prioritar është bllokimi i pacaktuar. Procesi që është i
gatshëm të ekzekutohet por nuk e ka në dispozicion procesorin do të konsiderohet i bllokuar.
Planifikimi prioritar mund të lë një grup të punëve me prioritet të ultë të presin pa kufizim për
procesor. Në sistemin e ngarkuar nga rrjedha e pandërprerë e punëve me prioritet të lartë, punët
me prioritet të vogël mund të mos arrijnë asnjëherë deri te procesori. Mund të ndodhë që ky lloj i
punëve të ekzekutohet një ditë kur ngarkesa të bie pak, por mund të ndodhë që nëse bie sistemi,
kjo punë të humbet.
Që ky problem të evitohet përdoret plakja. Plakja është teknikë e rritjes së prioritetit të
punëve që presin një kohë më të gjatë që të fitojnë procesorin. Mundemi p.sh. që me kalim të
intervalit të caktuar kohor punëve me prioritet të ultë t'ua rrisim prioritetin për 1 ashtu që në një
moment ato do të kenë prioritetin maksimal dhe do të ekzekutohen.

4.3.5 Algoritmet me përjashtim

Algoritmet I-pari-që-vjen-i-pari-shërbehet, Së-pari-puna-më-e-shkurtë dhe algoritmet


prioritare, ashtu si janë përshkruar deri tash i takojnë grupit të algoritmeve pa përjashtim (ang.
non-preemptive). Proceset që njëherë e kanë fituar procesorin nuk do ta lëshojnë deri në
momentin kur duhet të kryejnë operacionet hyrëse-dalëse ose deri kur të kryejnë ekzekutimin e
tyre. Algoritmi I-pari-që-vjen-i-pari-shërbehet është për nga natyra algoritëm pa përjashtim. Dy
algoritmet tjera mund të modifikohen ashtu që të bëhen algoritme me përjashtim.
Algoritmi Së-pari-puna-më-e-shkurtë mund të jetë pa përjashtim dhe me përjashtim.
Dallimi mes dy variantave të të njejtit algoritëm është në sjelljen e tyre në momentin e ardhjes së
procesit të ri në rreshtin e proceseve të gatshme. Nëse procesi i ri e ka më të shkurtë kohën e
breshërisë së ardhshme të procesorit, sesa është koha që i ka mbetur në dispozicion procesit që
momentalisht ekzekutohet, algoritmi me përjashtim do ta largojë procesin që ekzekutohet, ndërsa
algoritmi pa përjashtim do ta lë të përfundojë ekzekutimin e breshërisë së procesorit. Varianti më
përjashtim i algoritmit Së-pari-puna-më-e-shkurtë quhet edhe Së-pari-puna-me-kohë-të-mbetur-
më-të-shkurtë.

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.

4.3.6 Algoritmi i planifikimit rrethor

Planifikimi rrethor (ang. round-robin scheduling) i ekzekutimit të proceseve është i


dizajnuar posaçërisht për time-sharing sistemet operative. Me këtë rast definohet një njësi e vogël
e kohës e quajtur kuantum kohorë ose rriskë kohore. Ky kuantum kohorë është zakonisht prej 10
deri 100 milisekonda. Rreshti i proceseve të gatshme trajtohet si rresht cirkular. Planifikuesi
kohor ia jep secilit proces procesorin për interval të definuar me kuantumin kohorë.
Për ta implementuar këtë algoritëm, rreshti i proceseve të gatshme paraqitet si një rresht i
tipit I-pari-që-hyn-i-pari- del (FIFO rresht). Proceset e reja shtohen në fund të rreshtit.
Planifikuesi i procesorit e merr procesin e parë nga rreshti i proceseve të gatshme, e rregullon

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.

Fig.4.15 Kuantumi më i vogël kohor rrit numrin e shkëmbimeve të kontekstit

Tentohet që koha e shkëmbimit të kontekstit të jetë e vogël në krahasim me kuantumin


kohor. Nëse në sistem kemi vetëm një proces që zgjatë 10 njësi kohore atëherë për kuantum
kohor prej 12 njësish nuk do të kemi shkëmbim të kontekstit. Nëse kuantumi kohor është 6 njësi
kohore, procesi do të ndërprehet njëherë duke zgjatur kohën e ekzekutimit të tij për kohën e
nevojshme për kryerjen e një shkëmbimi të kontekstit. Është e qartë se kuantumi kohor prej një
njësie kohore do të ngadalsojë edhe më shumë ekzekutimin e procesit. Nëse koha e nevojshme
për shkëmbimin e kontekstit është përafërsisht sa 10 përqind e kuantumit kohor, atëherë
përafërsisht 10 përqind të kohës së procesorit do të shpenzohet në shkëmbimin e kontekstit
(Fig.4.15).
Shkëmbimi i kontekstit ndikon edhe në kohën e qëndrimit. Më shumë ndërrime të
kontekstit rrisin poashtu vlerën e kësaj madhësie.
Si rregull, në caktimin e raportit mes kohës për shkëmbimin e kontekstit dhe kuantumit
kohor mirret kërkesa që 80% të breshërive të procesorit të jenë më të shkurta se kohëzgjatja e
kuantumit kohor.

70
Fig.4.16 Koha mesatare e qëndrimit ndryshon me kuantumin kohor

4.3.7 Rreshtat shumënivelësh

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

Mes rreshtave duhet të ekzistojë poashtu njëfarë algoritmi i planifikimit. Zakonisht


zbatohet planifikimi me përjashtim në të cilin rreshtat kanë prioritet fiks.
Sistemi operativ OS/MFT i IBM-it i ka 5 rreshta të tillë. Në këta rreshta klasifikohen këto
punë:
- Punët e sistemit operativ,
- Programet interaktive,
- Editimi interaktiv,
- Batch punët,
- Punët e studentëve.
Çdo rresht ka prioritet absolut mbi rreshtin me prioritet më të ultë. Kjo do të thotë se asnjë batch
aplikacion nuk do ta fitojë procesorin në rastin kur cilido nga rreshtat e punëve të sistemit,
programeve interaktive ose editimit interaktiv nuk është i zbrazët. Në këtë sistem, arritja në
sistem e punës me prioritet më të lartë do të shkaktojë përjashtimin e punës me prioritet më të
ultë.
Rreshtave të ndryshëm mund tu jepet pjesë e caktuar e kohës së procesorit, për zgjedhjen
dhe ekzekutimin e proceseve që ndodhen në to. Shembull i këtij lloj organizimi të punës së
kompjuterit është që punëve interaktive tu jepet 80% të kohës së njësisë qendrore që me
planifikim rrethor ta shfrytëzojnë për ekzekutimin e punëve interaktive dhe 20% të kohës së
procesorit ti ndahet batch aplikacioneve që ekzekutohen në prapavijë, duke shfrytëzuar algoritmin

72
I-pari-që-vjen-i-pari-shërbehet.
4.3.8 Rreshtat shumënivelësh me riveprim

Në algoritmin paraprak punët janë në mënyrë permanente të vendosura në ndonjërin prej


rreshtave ekzistues në sistem. Nuk është i mundshëm kalimi i punëve nga një rresht në tjetrin.
Rreshtat shumënivelësh me riveprim mundësojnë që punët të kalojnë prej një rreshti në
tjetrin. Principi i ndarjes së punëve të ndryshme te ky lloj i algoritmit është që punët të vendosen
në rreshta të ndryshëm në bazë të cilësive të breshërive të procesorit. Nëse puna shfrytëzon
shumë kohë të procesorit do të vendoset në rrjeshin me prioritet të ultë. Punët që e shfrytëzojnë
procesorin për ekzekutimin e breshërive të shkurta do të vendosen në rreshta me prioritet më të
lartë. Kjo ndarje në siguron që punët e orientuara kah hyrja-dalja e të dhënave dhe punët
interaktive të kenë prioritet më të lartë. Ngjashëm mund të rregullohet që puna e prioritetit të ultë
me kalim të kohës të kalojë në rreshtin me prioritet më të lartë.

Fig.4.18 Rreshti shumënivelësh me riveprim

Të marrim parasysh planifikuesin që shfrytëzon rreshtin trinivelësh me riveprim


(Fig.4.18). Planifikuesi do ti ekzekutojë së pari të gjitha proceset nga rreshti 0, pastaj do të kalojë
në ata të rreshtit 1, por vetëm në rastin kur në rreshtin 0 nuk ka procese të gatshme. Proceset nga
rreshti 2 do të ekzekutohen vetëm në rastin kur rreshtat 0 dhe 1 nuk kanë procese të gatshme.
Ekzekutimi i procesit me prioritet më të ultë do të ndërprehet menjëherë në momentin kur në
rreshtin e prioritetit më të lartë të vij ndonjë proces. Kjo që u tha deri tash është e njejtë me atë që
thamë për rreshtat shumënivelësh pa riveprim. Dallimi mes këtyre dy algoritmeve qëndron në
këtë: Në momentin kur procesi të paraqitet në sistem, vendoset në rreshtin 0, në të cilin i jepet
kuantumi kohor prej ta zëmë 8 njësish kohore. Nëse procesi kryen ekzekutimin e vet brenda kësaj
kohe ose kërkon të kryej operacionet hyrëse-dalës do të çvendoset në fund të këtij rreshti. Nëse
procesi nuk arrin që të kryej ekzekutimin për shkak të skadimit të kuantumit të dhënë kohor do të
vendoset në fund të rreshtit 1. Proceset në rreshtin 1 e kanë kuantumin kohor dy herë më të
madh, në rastin tonë 16 milisekonda. Nëse procesi edhe në kuadër të këtij rreshti në momentin
kur ti vie rradha nuk arrin të kryej ekzekutimin në kuadër të kuantumit të dhënë kohor, do të
zhvendoset në rreshtin 2. Proceset në këtë rresht e kanë prioritetin më të vogël, por si kompenzim
fitojnë kohë më të gjatë të shfrytëzimit të procesorit, në rastin tonë 24 njësi kohore. Kuptohet,
mosshfrytëzimi i kuantumit kohor mund ta bie procesin nga rreshti me prioritet të ultë në rreshtin
me prioritet më të lartë, pra nga rreshti 2 në 1 ose nga rreshti 1 në atë 0.
Ky algoritëm siguron që punët e orientuara në hyrje-dalje ose komunikim interaktiv me

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.

4.4 Vlerësimi i algoritmeve

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.

4.4.1 Vlerësimi analitik

Vlerësimi analitik përdorë algoritmin që duam ta shqyrtojmë dhe ngarkesën punuese të


sistemit për të dhënë një formulë ose një numër. Kjo informatë e fituar na shërben që pastaj ta
rhemi mendimin tonë për algyritëm.

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:

Puna Koha e pritjes


1 0
2 10
3 39
4 42
5 49
që jep si mesatare vlerën 28.
Nëse përdorim algoritmin Së-pari-puna-më-e-shkurtë (pa përjashtim) punët ekzekutohen
si:

Puna Koha e pritjes


1 10
2 32
3 0
4 3
5 20
që jep kohën mesatare të pritjes 13 njësi kohore.
Te algoritmi rrethor me kuantum 10 njësi kohore do të kemi këtë diagram të kohëzgjatjes
së ekzekutimit të proceseve të përmendura.

Puna Koha e pritjes


1 0
2 32
3 20
4 23
5 40

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

Punët që ekzekutohen në sisteme kompjuterike ndryshojnë prej dite në ditë, kështu që


nuk ekziston ndonjë grup statik i punëve që do të mund të përdorej për të bërë vlerësimin e
algoritmeve ashtu si e kërkon modeli deterministik. Por, ajo çka mund të përcaktohet është
distribuimi i breshërive të procesorit dhe të operacioneve hyrëse-dalëse. Këto distribucione mund
të maten e pastaj të aproksimohen ose të vlerësohën. Rezultat i kësaj është formula matematikore
që shpreh gjasën e paraqitjes së breshërisë së procesorit me kohëzgjatje të caktuar. Zakonisht ky
distribucion është eksponencial. Ngjashëm, duhet të jepet edhe distribucioni i kohëve të arritjes së
punëve. Nga këto dy distribucione është e mundshme të llogaritet rendimenti mesatar,
shfrytëzimi, koha e pritjes etj. për shumicën e algoritmeve.
Sistemi kompjuterik mund të përshkruhet edhe si rrjetë e shërbyesve (ang. server). Çdo
server e ka rreshtin e punëve që presin. Procesori është server që ka rreshtin e proceseve të
gatshme, në të njejtën mënyrë siç është sistemi i hyrje-daljes me rreshtat e njësive. Duke ditur
kohët e arritjes dhe kohërat e shërbimit, mund të llogarisim shfrytëzimin, gjatësinë mesatare të
rreshtave, kohën mesatare të pritjes, etj.
Le të jetë p.sh. n gjatësia mesatare e rreshtit, pa përfshirë aty procesin që është duke u
ekzekutuar, le të jetë W koha mesatare e pritjes në rresht, ndërsa λ numri mesatar i proceseve të
reja që vijnë në rresht në njësi të kohës (p.sh. 3 procese në sekondë). Atëherë, mund të presim se
gjatë kohës W, që procesi e ka kaluar duke pritur, në rresht janë shtuar λ * W procese të reja.
Nëse sistemi është në gjendje stabile atëherë, numri i proceseve që vijnë do të jetë i barabartë me
numrin e proceseve që dalin nga sistemi. Në këtë mënyrë do të kemi:
n=λ*W
Ky ekuacion është i njohur si ekuacioni i Little-it. Ekuacioni i Little-it është i përdorshëm
posaçërisht, pasi vlen për çdo algoritëm dhe për çdo distribucion të ardhjes së proceseve.
Formula e Little-it përdoret për të llogaritur parametrin e tretë nëse i dijmë dy. Nëse e
dijmë se p.sh. 7 punë arrijnë mesatarisht çdo sekondë dhe se në rresht ka 14 punë, atëherë mund
ta llogarisim kohën mesatare të pritjes për secilin proces që do të na jep 2 sekonda.
Analiza e rreshtave mund të jetë e përshtatshme për krahasimin e algoritmeve, por ka
edhe kufizime të veta. Momentalisht numri i algoritmeve dhe distribucioneve të cilat mund të
shqyrtohen është mjaft i kufizuar. Aparati matematikor i përdorur poashtu nuk është i thjeshtë.
Distribucionet e ardhjes dhe shërbimit zakonisht definohen për kushte joreale që munden të
trajtohen matematikisht. Poashtu është e nevojshme të bëhen disa supozime të pavarura, të cilat
mund të jenë të pasakta. Në bazë të kësaj që u tha mund të konkludojmë se modelet e rreshtave
paraqesin një aproksimim të sistemit real. Saktësia e rezultateve të fituara në këtë mënyrë është e
diskutueshme.

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ë.

4.5 Planifikimi i më shumë procesorëve

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

Në kapitullin paraprak treguam se si një procesor mund të shfrytëzohet nga më shumë


procese, me qëllim të përmirësimit të performansave të procesorit. Që kjo të realizohet është e
nevojshme që më shumë procese ti mbajmë njëkohësisht në memorie.
Do të tregojmë në vazhdim disa mënyra të udhëheqjes me memorien operative të
kompjuterit.

5.1 Njoftime hyrëse

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.

Fig.5.1 Roli qendror i memories në sistemin memorik

Në të shumtën e rasteve programi i shfrytëzuesit kalon disa hapa para se të ekzekutohet


(Fig.5.2). Gjatë këtyre hapave adresat mund të jenë të prezentuara në mënyra të ndryshme.
Adresat në program burimor janë në përgjithësi simbolike, p.sh. x ose a. Kompajleri do ti lidh
këto adresa simbolike me adresa relokatibile që paraqesin adresa në raport me fillimin e këtij
moduli (p.sh. 24 bajtë nga fillimi i modulit). Louderi do ti shndërrojë këto adresa në adresa
absolute të memories operative (p.sh. 740FF). Çdo lidhje paraqet në fakt pasqyrim nga një
hapësirë adresore në tjetrën.
Programi do të mapohet në adresa absolute dhe si i tillë do të sjellet në memorie për tu
ekzekutuar. Gjatë ekzekutimit, programi do ti qaset instruksioneve dhe të dhënave nga memoria
duke gjeneruar adresat absolute të këtyre lokacioneve. Me të kryer të ekzekutimit, hapësira
memorike e programit deklarohet si e lirë, për të mundësuar sjelljen dhe ekzekutimin e programit
tjetër.
Një instruksion tipik së pari do të merr instruksionin nga memoria. Instruksioni do të
dekodohet dhe si rezultat i dekodimit mund të kemi qasje të re në memorie me qëllim të marrjes
së operandëve. Shumë shpesh, pasi ta ketë ekzekutuar instruksionin, procesori do ta ruajë
rezultatin në memorie. Gjatë krejt kësaj procedure njësia memorike sheh vetëm rrjedhë të
adresave memorike. Ajo nuk di si janë gjeneruar këto adresa, ose çka ndodhet në to (të dhëna ose
instruksione). Nga aspekti i problemit nga i cili e shqyrtojmë sjelljen e memories, nuk do të na
intereson si janë gjeneruar adresat. Në këtë pikëpamje programi është i lirë të përdorë çfarëdo
teknikash për gjenerimin e adresave. Neve na intereson vetëm sekuenca e adresave të gjeneruara
nga programi që ekzekutohet.

79
Fig.5.2 Hapat e përpunimit të programit të shfrytëzuesit

Do të trajtojmë disa mënyra të udhëheqjes me memorie. Zgjedhja e mënyrës së


udhëheqjes me memorie për sistem specifik do të varet nga shumë faktorë, por faktorë më me
rëndësi është arkitektura e zbatuar në sistem. Çdo algoritëm kërkon përkrahjen e vet hardverike.

5.2. Makina lakuriqe

Mënyra më e thjeshtë që sistemi operativ të zgjedhë problemin e udhëheqjes së mëmories


është që mos ta udhëheq fare. Shfrytëzuesi e ka në dispozicion tërë hapësirën memorike dhe ka

80
kontroll absolut mbi të.

Fig.5.3 Makina lakuriqe

Kjo qasje ka disa përparësi të padiskutueshme. Ajo i ofron shfrytëzuesit qasje më


fleksibile; memoria mund të kontrollohet në çfarëdo mënyre të dëshiruar. Thjeshtësia maksimale
dhe çmimi minimal janë të garantuar. Nuk ka nevojë për ekzistencën e hardverit special. Nuk
është as i nevojshëm softveri sistemor që trajton këtë problem.
Kufizim i qasjes së tillë është mungesa e plotë e çfarëdo shërbimi. Shfrytëzuesi ka kontroll
të plotë mbi kompjuter, por sistemi operativ nuk ofron përpunim të ndërprerjeve, nuk ka monitor
që do të përpunojë thirrjet sistemore ose gabimet dhe nuk ka hapësirë që të sigurojë sekuencimin
e punëve. Për shkak të gjithë kësaj që u tha, makina lakuriqe përdoret vetëm në ato sisteme që
janë të dedikuara për një punë të caktuar dhe për të cilat shfrytëzuesi nuk përton të shkruajë të
gjitha nënprogramet përkrahëse të nevojshme.

5.3 Monitori rezident

Skema e ardhshme më e thjeshtë është skema e ndarjes së memories në dy pjesë. Njëra


pjesë e memories do ti dedikohet shfrytëzuesit e tjetra do të përdoret për vendosjen e monitorit
rezident të sistemit operativ. Është e mundur që të vendosim monitorin në njërën ose tjetrën pjesë
të memories të njohura edhe si memorie e epërme (e lartë) dhe memorie e poshtme (e ultë). Se ku
do të vendoset monitori, do të varet kryesisht nga lokacioni i vektorit të ndërprerjes. Pasi vektori
i ndërprerjes është më shpesh në memorien e poshtme është bërë zakon që edhe monitori të
vendoset në memorien e poshtme.

81
Fig.5.4 Monitori rezident

5.3.1 Hardveri mbrojtës

Nëse monitori ndodhet në memorien e poshtme, ndërsa progra-mi i shfrytëzuesit


ekzekutohet në memorien e epërme, do të duhet ta mbrojmë kodin dhe të dhënat e monitorit nga
ndërrimi (i rastit ose qëllimkeq) i shkaktuar nga programi i shfrytëzuesit. Kjo mbrojtje duhet të
sigurohet me hardver dhe mund të implementohet në mënyra të ndryshme. Mënyra e
përgjithshme është që çdo adresë (e të dhënave ose instruksionit) e gjeneruar nga programi i
shfrytëzuesit të krahasohet me adresën kufitare (ang. fence address). Nëse adresa e gjeneruar
është e barabartë ose më e madhe se adresa kufitare atëherë është fjala për qasje legale memories
dhe adresa e tillë do të trajtohet si zakonisht. Nëse adresa e gjeneruar është më e vogël se kufiri,
atëherë kemi të bëjmë me referencë jolegale memories së monitorit. Kjo qasje e tentuar do të
parandalohet, me paraqitjen e ndërprerjes softverike (trepit) që do të sinjalizojë gabim adresor.
Sistemi operativ më pastaj do të ndërrmer aksion gjegjës (zakonisht largimi i programit nga
memoria dhe paraqitja e porosisë për gabim).
Pra, çdo referencë memories nga ana e programit të shfrytëzuesit do të kontrollohet. Në
përgjithësi ky kontrollim do të ngadalsojë kohën e qasjes memories për vlerën e kohës së
nevojshme për krahasim. Me projektim të kujdesshëm të qarqeve është e mundur që ky operacion
të ekzekutohet në të njejtën kohë kur kryhet edhe ndonjë aktivitet tjetër, duke redukuar kohën
efektive të qasjes.
Sistemi operativ që ekzekutohet në modin e supervisorit ka liri qasjeje edhe memories së
monitorit edhe memories së programit të shfrytëzuesit. Kjo i mundëson sistemit operativ që ti
sjellë programet e shfrytëzuesit në memorien e shfrytëzuesit dhe ti largojë nga ajo në rast të
kryerjes së ekzekutimit ose gabimit, që ti qaset dhe ti modifikojë parametrat e thirrjeve sistemore
etj.
Dallim qenësor mes sistemeve kompjuterike është mënyra në të cilën është e specifikuar
adresa kufitare. Kjo adresë mund të jetë e definuar në hardver.

82
Fig.5.5 Mbrojtja hardverike e adresave për monitorin rezident

Problemi me këtë adresë të definuar në hardverin e kompjuterit është zgjedhja e kësaj


adrese. Nëse adresa është shumë e vogël atëherë një pjesë e kodit të monitorit nuk do të jetë e
mbrojtur; nëse adresa është shumë e madhe një pjesë e memories që nuk i duhet monitorit do të
mbetet jashtë brezit që mund ta përdorë programi i shfrytëzuesit. Problem i vërtetë është fakti se
monitori si edhe çdo program tjetër mundet me kohë të bëhet më i madh ose më i vogël, duke e
bërë vlerën e zgjedhur njëherë të papranueshme për më vonë.
Që të zgjidhet ky problem zakonisht përdoret regjistri i kufirit (ang. fence register).
Regjistri i kufirit përmban adresën e kufirit dhe përdoret për të vërtetuar korektësinë e të gjitha
referencave të bëra memories nga ana e shfrytëzuesit. Vlera e ruajtur në këtë regjistër mund të
shkruhet nga ana e sistemit operativ me ekzekutimin e instruksionit special të privilegjuar.
Përmbajtja e regjistrit të kufirit mund të ndërrohet vetëm nga e programit që punon në modin e
supervisorit. Kjo i mundëson monitorit që ta ndërrojë vlerën e këtij regjistri çdoherë kur të
ndërron madhësia e monitorit.

5.3.2 Relokacioni

Problemi tjetër që duhet të merret parasysh është sjellja në memorie i programeve të


shfrytëzuesit. Edhepse hapësira adresore e kompjuterit fillon nga 00000, adresa e parë e
programit të shfrytëzuesit nuk është 00000, por adresa e parë pas kufirit. Ky rregullim i adresave
mund të ndikojë në adresat që përdorë programi i shfrytëzuesit. Lidhja e instruksioneve dhe të
dhënave të programit me adresat memorike mund të bëhet gjatë kompajlimit ose gjatë sjelljes në
memorie. Nëse adresa kufitare dihet në kohën e kompajlimit mund të gjenerohet kodi absolut. Ky
kod do të fillojë nga kufiri dhe do të zgjërohet kah adresat më të larta. Mirëpo, nëse adresa e
kufirit ndërron do të duhet të rikompajlohet programi. Alternativë kësaj mënyre të punës është
krijimi i kodit relokatibil (të zhvendosshëm) nga ana e kompajlerit. Në këtë rast lidhja e adresave
nuk do të bëhet deri në momentin e sjelljes në memorie. Nëse adresa e kufirit ndërron, programi
duhet vetëm të risjellet në memorie me qëllim të përshtatjes ndërrimit të bërë.
Në të dy rastet, kufiri duhet të jetë statik gjatë ekzekutimit të programit. Nëse adresat

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.

Fig.5.6 Sjellja e shfrytëzuesit në memorien e epërme

Qasje më e përgjithshme këtij problemi, e zbatuar te kompjuterët CDC 6600, është që


lidhja e adresave të shtyhet deri në momentin e ekzekutimit të programit. Kjo skemë dinamike e
relokacionit shfrytëzon hardver tjetër për të përkrahur realizimin e mënyrës së menduar. Regjistri
i kufirit tani quhet regjistër i bazës ose i relokacionit. Vlera e regjistrit të bazës i shtohet secilës
adresë të gjeneruar nga procesi i shfrytëzuesit. P.sh. nëse kufiri është në 1600 atëherë tentimi i
procesit të shfrytëzuesit ti qaset adresës 0 do të bartet dinamikisht në qasje adresës 1600; qasja
adresës 246 do të shndërrohet në qasje adresës 1846.

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).

Fig.5.8 Zëvendsimi i dy shfrytëzuesve me përdorimin e diskut si njësi përkrahëse

5.4.1 Njësia përkrahëse

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.

5.4.2 Koha e zëvendsimit

Element me rëndësi në operacionet e përshkruara më lartë është koha e nevojshme për


kryerjen e tyre. Që të kemi njëfarë dijenie se sa zgjatë zëvendsimi, të marrim një sistem që ka si
njësi përkrahëse një disk me kohë të vonesës (ang. latency time) prej 8 milisekondash dhe
shpejtësi të transferit të të dhënave prej 250 KW/s (kilofjalë në sekond). Transferi i programit që
ka 20,000 fjalë nga memoria në disk ose anasjelltas do të zgjatë:

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.

5.4.3 Përputhja kohore e zëvendsimit dhe operacioneve tjera

Efekti i zëvendsimit në kohën e shkëmbimit të kontekstit mund të zvoglohet duke


përputhur në kohë zëvendsimin me ekzekutimin e programit. Qëllimi i jonë do të jetë që
zëvendsimin e njërit proces ta bëjmë në kohën e ekzekutimit të një procesi tjetër. Në këtë mënyrë
procesori nuk do të rri i papunë derisa të bëhet zëvendsimi. Derisa një proces ekzekutohet, një
tjetër do të nxjerret nga baferi 1, e procesi që do të ekzekutohet në vazhdim do të sjellet në
baferin 2.

Fig.5.9 Zëvendsimi i kombinuar në kohë me operacione tjera

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.

Fig.5.10 Tentim i ekzekutimit të programit me zhvendosje të kufirit

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

Konfiguracioni memorik që del nga zëvendsimi i përputhur me ekzekutimin e programeve


tjera është në esencë i njejtë me konfiguracionin memorik për multiprogramim: në memorie kemi
njëkohësisht më shumë programe. Te multiprogramimi procesori do të kalojë shpejtë nga njëri
proces në tjetri. Problemi i udhëheqjes me memorie është ndarja e memories programeve të
shumtë që ndodhen në grupin e punëve që presin të ekzekutohen.
Memoria është e ndarë në regjione ose particione. Secili regjion mund ta ketë një
program për ekzekutim. Në këtë mënyrë shkalla e multiprogramimit do të jetë e kufizuar me
numrin e regjioneve. Kur regjioni është i lirë nga rreshti i punëve zgjedhet një program dhe sjellet
në regjionin e lirë. Kur të kryhet ekzekutimi i tij, regjioni vëhet në dispozicion programeve tjera.
Ekzistojnë dy skema të udhëheqjes së memories së tillë. Të dy skemat e ndajnë memorien
në regjione ose particione. Dallimi mes këtyre dy qasjeve është se a do të jenë këto regjione
statike ose dinamike. Këto dy skema janë të njohura si: vendosja në particione të
shumëfishta të pandërprera fikse dhe vendosja në particione të shumëfishta të
pandërprera variabile. Shembuj më të njohur të këtyre skemave janë MFT (ang.
multiprogramming with a fixed number of tasks, shq. multiprogramimi me numër fiks të
proceseve) dhe MVT (ang. multiprogramming with a variable number of tasks, shq.
multiprogramimi me numër variabil të proceseve) verzionet e sistemit operativ OS/360 të IBM-
ës.

5.5.1 Hardveri mbrojtës

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).

Fig.5.11 Dy regjistra të kufirit definojnë hapësirën logjike adresore

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

5.5.2 Regjionet fikse (MFT)

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

Planifikimi i punëve në MFT

Me të hyrë në sistem, puna e ardhur vendoset në rreshtin e punëve. Planifikuesi i punëve


merr parasysh kërkesat memorike të secilës punë dhe regjionet memorike në dispozicion për të
vendosur cilës punës do ti jepet memoria. Kur punës ti ndahet hapësira memorike, ajo do të sjellet
në memorie (nëse është e nevojshme do të bëhet relokacioni). Pasi të jetë vendosur në memorie,
puna mund të konkurojë për kohën e procesorit. Kur puna të kryhet, ajo do ta liron regjionin
memorik të cilin mund ta shfrytëzojë puna tjetër e zgjedhur nga planifikuesi i punëve.
Në caktimin e memories së nevojshme për punë mund të përdoren mënyra të ndryshme.
Një strategji parasheh që punët të klasifikohen me të hyrë në sistem, në bazë të kërkesave për
memorie. Ky klasifikim mund të bëhet duke kërkuar nga shfrytëzuesi që të specifikojë sasinë
maksimale të nevojshme të memories. Zgjidhje alternative është që sistemi të provojë të
përcaktojë automatikisht kërkesat memorike. Secili regjion memorik ka rreshtin e vet të punëve
(Fig.5.13). Klasifikimi i punëve përdoret për të zgjedhur rreshtin gjegjës për punë.

Fig.5.13 MFT me rreshta të veçantë për secilin regjion

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.

Fig.5.14 MFT me rresht unik

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

Zgjedhja e madhësisë adekuate të regjioneve memorike është problem që ngarkon


udhëheqjen memorike me regjione fikse. Pasi ta kemi ndarë hapësirën për monitor na mbetet të
vendosim se si do ta ndajmë hapësirën e mbetur. Duhet të vendosim se në sa regjione do të
ndajmë dhe të çfarë madhësisë do të jenë këto regjione. Ndarja fillestare bëhet në bazë të
supozimeve për kërkesat e punëve që do të ekzekutohen në sistem.
Pasi sistemi të fillon të punojë, do të mbledhim informatat për numrin e punëve që
ekzekutohen dhe kërkesat e vërteta për memorie. Nga këto të dhëna statistikore mund të
konkludojmë a e kemi bërë zgjedhjen e mirë të numrit dhe madhësisë së regjioneve.
Gjetja e madhësisë optimale të regjioneve është çështje qenësore për MFT-ën.
Performansat e sistemit kompjuterik varen drejtëpërdrejtë nga niveli i multiprogramimit, e ky nga
ana tjetër varet nga suksesi i udhëheqjes me memorie. Nëse gjysma e memories nuk përdoret,
atëherë kjo do të thotë se nëse gjejmë mundësi që këtë memorie të përdorim, do të mund të
ekzekutonim dy herë më shumë punë.

Fragmentimi i memories

Puna që ka nevojë për m fjalë memorike mund të ekzekutohet në regjionin që ka n fjalë,


me kusht që n≥m. Ndryshimi mes këtyre dy madhësive (n-m) paraqet fragmentimin intern
(copëzimin e brendshëm). Fragmentimi intern është pra memoria që i takon regjionit por nuk
shfrytëzohet. Fragmentimi ekstern (copëzimi i jashtëm) paraqitet kur regjioni është i
pashfrytëzuar dhe në dispozicion, por i vogël për cilëndo nga punët që presin. Të dy tipet e
fragmentimit janë burime të humbjeve memorike në MFT.
Për shembull, nëse kemi memorien 32K dhe nga kjo memorie 10K i rezervojmë për
monitor, atëherë memorien e mbetur mund ta ndajmë ne disa regjione. Ta zëmë se ndarja ëshët
bërë në një regjion 10K dhe tre regjione nga 4K. Nëse rreshti i punëve ka punë që kërkojnë
respektivisht 7K, 3K, 6K dhe 6K, atëherë punën e parë do të mund ta vendosnim në regjionin
10K e punën 2 në njërin nga regjionet me 4K memorie. Kjo vendosje do të shkaktojë fragmentim
të brendshëm dhe ate 3K për punën e parë dhe 1K për punën e dytë. Pasi dy punët tjera nuk
mund të vendosen në regjionet me nga 4K kjo hapësirë mbetet e pashfrytëzuar duke dhënë 8K të
fragmentimit ekstern. Fragmentimi i përgjithshëm është 12K që është e barabartë me kërkesat
memorike të dy punëve që nuk mund të ekzekutohen dhe paraqet më shumë se gjysmën e
memories së lënë në dispozicion shfryrtëzuesve.
Nëse memorien e ndajmë ne regjione prej 10K, 8K dhe 4K, do të mund të startonim
punën 1 në regjionin 8K (fragmentimi intern 1K) dhe punën 2 në regjioni 4K (fragmentimi intern
1K). Varësisht nga planifikuesi i përdorur i punëve mundemi që punët 6K ti lëmë të presin për
regjionin 8K (duke krijuar fragmentim ektern prej 10K) ose të startojmë ekzekutimin e njërës prej
tyre në regjionin 10K duke krijuar fragmentim intern 4K, por duke eliminuar fragmentimin
ekstern. Sikur regjionet ti ndanim sipas kërkesave të punëve, atëherë do të ishim në gjendje që të
katër punët ti ekzekutojmë pa fragmentim intern ose ekstern (kërkesat e punëve janë 7K + 3K +
6K + 6K = 22K sa është madhësia e memories së lënë në dispozicion shfrytëzuesve).

5.5.3 Particionet variabile

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.

Fig.5.15 Shembull i planifikimit MVT

Të marrim se kemi memorien 256K në të cilën ndodhet monitori që zë 40K (Fig.5.15).


Për shfrytëzues mbeten 216K. Nëse kemi rreshtin e dhënë të punëve:

Puna Memoria Koha


1 60K 10
2 100K 5
3 30K 20
4 70K 8
5 50K 15

dhe planifikimin I-pari-që-vjen-i-pari-shërbehet të punëve, mundemi menjëherë t'ia ndajmë


memorien punëve 1, 2 dhe 3, duke krijuar kartën e memories si në Fig.5.16a. Na mbetet 26K
fragmentim ekstern. Duke shfrytëzuar planifikimin rrethor të procesorit me kuantum prej 1 njësie
kohore, puna 2 do të kryhet në momentin kohor 14 duke liruar hapësirën e zënë memorike. Kjo
jep kartën e memories të dhënë në vazhdim (Fig5.16b). Do ti kthehemi tani planifikuesit të
punëve dhe do të zgjedhim punën 4, pas vendosjes të së cilës në memorie do të kemi pamjen e
memories si në Fig.5.16c. Në momentin 28 do të përfundojë ekzekutimin puna 1 duke dhënë
memorien nga Fig.5.16d. Vendosja e punës 5 jep pamjen e memories si në Fig.5.16e.

95
Fig.5.16 Shembull i vendosjes memorike dhe planifikimit të punëve MVT

Ky shembull tregon disa karakteristika të MVT-ës. Në përgjithësi, në çfarëdo momenti


kohor, ekziston grupi i vrimave të madhësive të ndryshme të shpërndara kudo nëpër memorie.
Kur të arrijë puna, kërkohet ky grup i vrimave pët tu gjetë vrima mjaft e madhe për këtë punë.
Nëse vrima është më e madhe se sa duhet, do të ndahet në dysh. Një pjesë do ti jepet punës, tjetra
do ti kthehet grupit të vrimave. Kur puna të përfundojë, ajo do ta liron memorien e cila përsëri do
të vendoset në grupin e vrimave. Nëse vrima e krijuar është ngjit me një vrimë tjetër, atëherë nga
këto dy do të krijojmë një vrimë të re më të madhe. Në këtë moment, duhet të kontrolluar
rreshtin e punëve që presin për të parë nëse ka ndonjë punë që pret për vrimë të madhësisë së
vrimës së re të krijuar. Nëse ka, puna do të sjellet në vrimën e krijuar.
Pasi ti jetë dhënë memoria, puna mund të sjellet në te dhe të ekzekutohet. Përkrahja
minimale hardverike e nevojshme është e njejtë me kërkesat e MFT; pra, dy regjistra të kufirit të
poshtëm dhe të epërm të regjionit të dhënë punës. Kur planifikuesi i punëve ta zgjedh këtë
proces, dispeçeri do të mbush këta dy regjistra me vlera gjegjëse. Pasi çdo adresë e gjeneruar do
të krahasohet me këto dy vlera, programet dhe të dhënat e shfrytëzuesve tjerë do të mund të
mbrohen nga ky proces që ekzekutohet.
Nga kjo konkludojmë se dallimi mes MVT dhe MFT është në softver e jo në hardver që
përkrah këto dy strategji të udhëheqjes së memories.
Nëse kërkesa për memorie është pak më e vogël se vrima e cila mund të kënaq kërkesën
paraqitet problemi i mirëmbajtjes së informatave të nevojshme për këtë vrimë të
pashfrytëzueshme (mund të jetë e rendit disa bajtë). Që të zgjidhë këtë problem MVT fut një
dozë të vogël të fragmentimit intern duke ia dhënë punës, në disa raste, vrimën që është më e
madhe se kërkesa e punës. Sistemet e ndryshme e ndajnë memorien në sasi që nuk janë më të
vogla se p.sh. 8 fjalë, 64fjalë, 2kbajtë ose ndonjë vlerë tjetër (Fig.5.17).

96
Fig.5.17 Vendosja është e kufizuar në shumëfisha të një madhësie themelore

Planifiki i punëve MVT

MVT-ja është e lidhur ngusht me planifikimin e punëve. Në çdo moment në sistem


ekziston lista e blloqeve memorike në dispozicion dhe rreshti i punëve që kërkojnë memorie.
Planifikuesi i punëve mund të rendit rreshtin e punëve në bazë të algoritmit të planifikimit. Këtyre
punëve do tu jepet memoria deri në momentin kur kërkesat e njërës punë nuk mund të kënaqen,
pra deri kur në sistem nuk eziston asnjë vrimë e madhësisë së kërkuar. Në këtë moment
planifikuesi i punëve mund të pret deri sa të lirohet blloku i madhësisë së dëshiruar, ose mund të
kërkojë në rreshtin e punëve ndonjë punë të prioritetit më të ultë me kërkesa më modeste për
memorie. Këto dy qasje paraqesin rastet e planifikimit të procesorit me kërcim ose pa të.
Shfrytëzimi i memories për MVT është, në rastin e përgjithshëm, më i mirë se te MFT.
Fragmentim intern nuk ka ose ka shumë pak, për arsye se madhësia e regjioneve caktohet në bazë
të kërkesave të punës. Por, kemi fragmentim ekstern. Ky fragmentim mund të shkaktojë që
edhepse madhësia e vrimave së bashku është më e madhe se kërkesat e punëve të veçanta, për
shkak se madhësia e pamjaftueshme e secilës prej tyre nuk kënaq kërkesat, nuk është e mundur
sjellja e punëve në to.
Problemi i fragmentimit ekstern mund të jetë shumë i ashpër. Në rastin më të keq mund të
kemi bllok të lirë (të pashfrytëzueshëm) të memories ndërmjet çdo dy punëve. Sikur e tërë kjo
memorie e lirë të ndodhej në një vrimë, ndoshta do të mund të ekzekutohej edhe ndonjë punë
tjetër. Në shkallën e fragmentimit mund të ndikojë edhe zgjedhja mes regjionit që i pari përgjigjet
dhe regjionit që më së miri përgjigjet. Në fragmentim ndikon edhe cilën pjesë të vrimës do t'ia
ndajmë procesit (të epërmen ose të poshtmen). Cilido algoritëm që të përdorim gjithmonë do të
kemi fragmentim ekstern.

Kompaktëzimi

Fragmentimin ekstern mund ta eliminojmë ose së paku ta zvoglojmë duke bërë


kompaktëzimin. Qëllimi është që përmbajtjet në memorie të zhvendosen ashtu që të krijohet një
vrimë e madhe e memories së lirë. Kompaktëzimi mund të bëhet ashtu siç është treguar në figurën

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:

p = U div P dhe d = U mod P

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

5.6.2 Planifikimi kohor i punëve

Si edhe përpara, mënyra e udhëheqjes së memories ndikon në planifikuesin e punëve. Kur


një punë të vijë në sistem, planifikuesi i punëve do të shqyrtojë madhësinë e saj. Madhësia e punës
do të shprehet në faqe. Planifikuesi do të kontrollojë memorien në dispozicion për të gjetur n
korniza të lira, nëse madhësia e punës është n faqe. Nëse në memorie ekzistojnë n korniza të lira,
atëherë ato do ti ndahen punës. Faqja e parë e punës do të vendoset në njërën nga kornizat e
dhëna, ndërsa numri i kornizës do të vendoset në tabelën e faqeve të asaj pune. Edhe faqja e dytë
do të vendoset në kornizën e ardhshme, e numri i kornizës si edhe më parë do të vendoset në
tabelën e faqeve të punës. Kështu veprohet me të gjitha faqet e punës (Fig.5.23).
Kjo mënyrë e udhëheqjes me memorie na liron nga fragmentimi i jashtëm. Cilado kornizë
e lirë mund ti ndahet punës që e kërkon. Fragmentimi i brendshëm paraqitet për arsye se kornizat
u ndahen punëve si njësi të pandashme. Nëse madhësia e programit nuk mund të shprehet
saktësisht si shumëfish i faqeve, korniza

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.

5.6.3 Implementimi i tabelës së faqeve

Është interesant implementimi hardverik i tabelës së faqeve. Në rastin më të thjeshtë, ajo


mund të implementohet si grup i regjistrave me destinim të posaçëm. Dispeçeri i procesorit do ti
mbushë këta regjistra në të njejtën mënyrë si ia bën me regjistrat tjerë. Instruksionet për ndërrimin
ose shkruarjen në regjistrat e tabelës së faqeve janë instruksione të privilegjuara të cilat mund ti
kryejë vetëm sistemi operativ. Varësisht nga madhësia e memories dhe numri i faqeve, numri i
këtyre regjistrave shkon prej 8 deri 256. Nuk janë të përjashtuara vlera tjera. Regjistrat e tabelës
së faqeve duhet të jenë shumë të shpejtë për të mundësuar përkthimin efikas të adresave logjike
në fizike. Pasi çdo qasje memories duhet të shkojë përmes kësaj tabele efikasiteti është çështje
qenësore.
Përdorimi i regjistrave për vendosjen e tabelës së faqeve është i arsyeshëm vetëm në rastin
kur tabela është relativisht e vogël. Mirëpo pasi numri i faqeve është në shumicën e sistemeve
dukshëm më i madh (në sistemin operativ Multics mund të kemi deri 16,777,216 faqe)
implementimi i tabelës në regjistra është i parealizueshëm. Për këtë arsye tabela e faqeve ruhet në
memorie operative. Në vendin e tabelës në memorie tregon përmbajtja e regjistrit tregues të
bazës së tabelës së faqeve (ang. Page Table Base Register, PTBR). Ndërrimi i tabelave të faqeve
realizohet me ndërrimin e përmbajtjes së këtij regjistri.
Problemi me këtë mënyrë të punës është koha e nevojshme për qasje lokacionit memorik
të shfrytëzuesit. Nëse dëshirojmë ti qasemi lokacionit i atëherë duhet të bëjmë dy qasje në
memorie. Njëra qasje do të jetë për të mësuar numrin e kornizës dhe zhvendosjen që do të na jep
adresën e vërtetë. Pasi ta kemi fituar këtë adresë mund ti qasemi lokacionit të dëshiruar në
memorie. Qasja tabelës së faqeve e pastaj edhe vetë lokacionit e përgjysmon shpejtësinë e punës
së memories.
Ky problem zgjidhet me përdorimin e memories speciale e quajtur regjistra asociativ ose
cache memories ose "shiko-anash" memories (ang. look-aside memory) ose memorie e adresuar
në bazë të përmbajtjes (content-addressable memory). Një grup i regjistrave asociativ, i ndërtuar
nga elemente jashtëzakonisht të shpejta, përdoret për këtë qëllim. Çdo regjistër nga ky grup është
i ndarë në dy pjesë: në pjesën ku ruhet qelësi dhe pjesën ku ruhet vlera. Kur regjistrave asociativ
iu bëhet e njohur një përmbajtje, kjo përmbajtje do të krahasohet me të gjithë qelësat. Nëse
përmbajtja e njejtë gjindet në ndonjërin nga regjistrat, vlera gjegjëse nga ky regjistër do të jetë
dalje. Kërkimi është shumë i shpejtë. Hardveri - shumë i shtrenjtë.
Në lidhje me tabelat e faqeve regjistrat asociativ kanë këtë përdorim: Regjistrat asociativ
përmbajnë vetëm disa nga elementet e tabelës së faqeve. Në momentin kur të gjenerohet adresa
logjike nga ana e procesorit, numri i faqes së saj i paraqitet grupit të regjistrave asociativ që
përmbajnë numrat e faqeve dhe numrat e kornizave gjegjëse. Nëse numri i faqes gjindet në
regjistrat asociativ, numri i kornizës gjegjëse do të jetë momentalisht në dispozicion për qasje

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).

5.6.4 Faqet e përbashkëta

Përparësi tjetër e faqëzimit është mudësia e ndarjes (shfrytëzimit të përbashkët) të kodit të


përbashkët. Kjo është posaçërisht e rëndësishme në time-sharing sistemet. Të marrim se në sistem
janë 40 shfrytëzues që e përdorin të njejtin editor për të skruar tekste. Nëse tekst editori është
30K dhe të dhënat që shfrytëzon zënë 5K, atëherë për 40 shfrytëzues do të na nevojiteshin 1400K
memorie. Nëse kodi i editorit është rihyrës (ang. reentrant) ai do të mund të shfrytëzohet nga më
shumë shfrytëzues njëkohësisht. Në Fig.5.24 është dhënë rasti i editorit që shfrytëzohet nga 3
procese. Secili proces e ka nga një faqe të veçantë për të dhëna.
Kodi rihyrës (i quajtur edhe kod i pastër ang. pure code) është kod vetë-jo-modifikues
(ang. non-self-modifying). Nëse kodi është rihyrës atëherë ai nuk ndërron asnjëherë gjatë
ekzekutimit. Kjo mundëson që dy procese ta ekzekutojnë të njejtin kod në të njejtën kohë. Çdo
proces e ka kopjen e regjistrave të vet dhe hapësirës memorike për ruajtjen e të dhënave gjatë
ekzekutimit të tij. Të dhënat për dy procese të ndryshme kuptohet se mund të ndryshojnë.

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

Mbrojtja e memories në rrethinën e faqëzuar (ang. paged environment) realizohet me


ndihmën e bitëve mbrojtës për secilën faqe. Këta bita ruhen në tabelën e faqeve. Një bit tregon a
është fjala për faqe vetëm për lexim apo për lexim dhe shkruarje. E dijmë se çdo qasje memories
shkon nëpër tabelën e faqeve me qëllim të gjetjes së numrit të kornizës. Gjatë kësaj kohe mund të
bëhet edhe kontrolli i bitit të mbrojtjes. Tentimi i shkruarjes në faqe që është vetëm për lexim do
të shkaktojë ndërpreje hardverike (ndërprerja e njohur si memory protection violation).
Kjo qasje mund të zgjerohet me qëllim të ofrimit të mbrojtjes më të diferencuar. Hardveri

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.

Fig.5.25 Biti i validitetit në tabelën e faqeve

Adresat jovalide detektohen përmes bitit të validitetit. Sistemi operativ do të definojë


vlerën e këtij biti për secilën faqe për të lejuar ose ndaluar qasjen asaj faqeje. Për shembull në
sistemin me hapësirë adresore 14 bitëshe (0 deri 16838), mund të kemi programin që shfrytëzon
adresat prej 0 deri 10468. Nëse faqja është 2K, do të kemi situatën si në Fig.5.25. Adresat në
faqet 0, 1, 2, 3, 4 dhe 5 janë të mapuara normalisht përmes tabelës së faqeve. Tentimi i gjenerimit
të adresës në faqet 6 ose 7 do të gjejë bitin e validitetit në gjendje jovalide, që do të shkaktojë
ndërprerje (ndërpreja invalid page reference).
Duhet vërejtur në këtë rast se çdo tentim qasjeje adresave më të mëdha se 10468 është
jolegal. Por qasja faqes 5 është definuar si valide kështuqë adresat deri 12287 janë valide. Vetëm
adresat prej 12288 deri 16383 janë jovalide. Kjo është rezultat i madhësisë së faqes (2K) dhe
paraqet fragmentimin intern të faqëzimit.
5.6.6 Dy këndvështrime memories

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

Do të paraqesim në vazhdim një qasje tjetër udhëheqjes së memories që është e njohur si


segmentim (ang. segmentation). Për fillim do ti kthehemi edhe një herë problemit se si e sheh
shfrytëzuesi memorien.

5.7.1 Këndvështrimi i shfrytëzuesit i memories

Është përshtypje e përgjithshme se shfrytëzuesi ose programeri nuk e shikojnë memorien


si një fushë lineare të fjalëve ose bajtëve, disa prej të cilëve përmbajnë instruksione e të tjerët të
dhëna. Shikim i preferuar i tyre është që memorien ta trajtojnë si një përmbledhje të segmenteve
të ndryshme për kah madhësia mes ta cilëve nuk ekziston ndonjë renditje e posaçme.

109
Fig.5.26 Këndvështrimi i shfrytëzuesit i memories

Kur programeri e shkruan një program ai ka parasysh programin kryesor, nënprogramet,


procedurat, funksionet. Programi shfrytëzon struktura të ndryshme të të dhënave, tabela, fusha,
variabla, konstante etj. Gjatë kësaj pune shumë pak ose aspak kujdes nuk i kushtohet vendit ku
do të vendosen këto module ose të dhëna. Këtyre elementeve u referohemi përmes emrit dhe
është krejt njësoj se a ndodhen fizikisht në memorie të dhënat para ose pas funksionit. Secili grup
i të dhënave ose kodit të tillë do të trajtohet si një segment i gjatësisë së ndryshueshme. Gjatësia e
segmentit është vetëvetiu e definuar nga destinimi i segmentit në program. Elementet në kuadër të
segmentit janë të definuar përmes zhvendosjes nga fillimi i segmentit, si p.sh. rreshti i tretë i
matricës, instruksioni i 15 i programit, etj.
Segmentimi është mënyrë e udhëheqjes së memories që përkrah këtë pamje të memories
nga ana e shfrytëzuesit. Hapësira adresore logjike është përmbledhje e segmenteve. Çdo segment
e ka emrin dhe gjatësinë. Adresat tregojnë segmentin dhe zhvendosjen në kuadër të segmentit.
Shfrytëzuesi do të specifikojë secilën adresë me dy madhësi: emrin e segmentit dhe zhvendosjen.
Për thjeshtim të punës segmentet janë të numëruara dhe atyre u referohemi zakonisht
përmes numrit e jo përmes emrit. Programi i shfrytëzuesit do të asemblohet ose kompajlohet dhe
asembleri ose kompajleri do të konstruktojë automatikisht segmentet që do ti përgjigjen

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

Edhepse shfrytëzuesi mund tu referohet objekteve në program përmes adresës


dydimensionale segment-zhvendosje, memoria fizike është edhe më tutje sekuencë
njëdimenzionale e fjalëve. Na duhet pra të definojmë implementimin e adresave dydimensionale të
gjeneruara nga shfrytëzuesi në adresa fizike njëdimensionale. Ky mapim bëhet me ndihmën e
tabelës së segmenteve.
Përdorimi i tabelës së segmenteve është treguar në figurën 5.28. Adresa logjike përbëhet
nga dy pjesë: numri i segmentit s dhe dhe zhvendosja në kuadër të segmentit d. Numri i segmentit
shërben si indeks në tabelën e segmenteve. Çdo hyrje në tabelën e segmenteve e ka bazën e
segmentit dhe limitin e segmentit. Zhvendosja d nga adresa logjike duhet të jetë në brezin prej 0
deri te limiti. Nëse nuk është do të kemi ndërprerje (ndërprerja tentim adresimi logjik jashta limitit
të segmentit). Nëse zhvendosja është në kuadër të vlerave të lejuara (më e vogël se limiti) do ti
shtohet bazës së segmentit për të dhënë adresën fizike të dëshiruar. Tabela e segmenteve është në
esencë fushë e çifteve të regjistrave bazë/limit.
Të marrim për shembull situatën nga figura 5.29. Pesë segmentet e treguara i kanë numrat
prej 0 deri 4. Segmentet janë të vendosura në memorie ashtu si është paraqitur në skajin e djathtë
të figurës. Tabela e segmenteve e ka nga një hyrje për secilin segment ku është e dhënë adresa e
bazës së segmentit (adresa fizike e fillimit të segmentit) dhe gjatësia e segmentit (limiti). Segmenti
2 është për shembull i vendosur duke filluar prej lokacionit 4300 dhe është i gjatë 400 fjalë. Qasja
fjalës 53 të segmentit 2 ka të bëjë me qasje lokacionit 4300 + 53 = 4353. Referenca e bërë
sementit 3, fjalës 852 do të mapohet në 3200 + 852 = 4052. referenca e bërë fjalës 1222 të
segmentit 0 do të shkaktojë ndërprerje pasi segmenti 0 është i gjatë vetëm 1000 fjalë.

111
Fig.5.27 Hardveri i segmentimit

5.7.3 Implementimi i tabelës së segmenteve

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

5.7.4 Mbrojtja dhe shfrytëzimi i përbashkët

Përparësi e veçantë e segmentimit është ndërlidhja kuptimore e segmenteve me mbrojtjen.


Pasi segmentet paraqesin pjesë programore të definuar në pikëpamje kuptimore (semantike) është
gjasa e madhe se të gjitha të dhënat në atë segment përdoren në të njejtën mënyrë. Shumë shpesh
kemi segmente që përmbajnë vetëm instruksione dhe segmente që përmbajnë vetëm të dhëna.
Nëse instruksionet janë jo-vetë-modifikuese atëherë segmenti i instruksioneve mund të caktohet
vetëm për lexim ose vetëm për ekzekutim. Hardveri që bënë mapimin do të kujdeset që të mos
lejohet shkruarja në segmentin që është vetëm për lexim ose që p.sh. segmenti që është vetëm për
ekzekutim të përdoret si segment për të dhëna. Ky kontroll bëhet duke analizuar gjendjen e bitave
të mbrojtjes. Segmentimi i memories poashtu mundëson që shumë gabime programore të
detektohen nga hardveri para se të shkaktojnë ndonjë dëm.
Përparësi tjetër e segmentimit është përdorimi i kodit ose të dhënave të përbashkëta.
Secila punë e ka tabelën e segmenteve që është e lidhur me bllokun kontrollues të procesit i cili
shfrytëzohet nga ana e dispeçerit për të caktuar tabelën hardverike të segmenteve në momentin
kur kësaj pune ti jepet procesori. Segmentet janë të shfrytëzuar së bashku (ang. shared) kur hyrjet
në tabelat e segmenteve të dy punëve të ndryshme tregojnë në lokacione të njejta fizike. Ilustrimi
është dhënë në figurën 5.31.
Shfrytëzimi i përbashkët bëhet në nivel të segmenteve. Secila informatë mund të
shfrytëzohet bashkarisht vetëm nëse definohet si segment. Kështu mund të shfrytëzohen së
bashku më shumë segmente, kështuqë programi i përbërë nga më shumë segmente mund të
shfrytëzohet bashkarisht.
Do të marrim përsëri shembullin e editorit në time-sharing sistem. Editori komplet mund
të jetë i madh, i përbërë nga më shumë segmente. Këto segmente mund të shfrytëzohen
bashkarisht nga më shumë shfrytëzues. Në vend të n kopjeve do të kemi vetëm një kopje të
editorit. Si edhe te faqëzimi secili shfrytëzues duhet të ketë segmentin e vet të të dhënave, në të
cilin do ti ruajë variablat lokale.
Është i mundur shfrytëzimi i përbashkët i vetëm pjesëve të programeve. Rast tipik është
përdorimi i nënprogrameve që shfrytëzuesit mund ti definojnë si segmente të përbashkëta që
vetëm mund të lexohen. Mund të kemi rastin kur dy programe përdorin të njejtin nënprogram për
llogaritjen e rrënjës katrore duke iu qasur një kopjeje fizike të nënprogramit të përmendur.
Ka disa probleme në lidhje me shfrytëzimin e përbashkët të segmenteve. Segmentet
zakonisht përmbajnë referenca ndaj vetëvetes. P.sh. kërcimi me kusht ka zakonisht transfer
adresën. Kjo adresë përbëhet nga numri i segmetit dhe zhvendosja. Numri i segmentit të transfer
adresës do të jetë numri i segmentit të segmentit të kodit. Nëse dëshirojmë ta shfrytëzojmë
bashkarisht këtë segment të gjitha proceset duhet ta definojnë një numër të njejtë për këtë
segment që do të përdoret si numër i segmentit.

114
Fig.5.30 Përdorimi i përbashkët i segmenteve në sistemin memorik të segmentuar

Që kjo që thamë te jëtë më e kjartë të marrim se segmentin ku ndodhet kodi për


llogaritjen e rrënjës katrore një proces do ta merr si segment numër 4 e tjetri si segment numër
15. Shtrohet pyetja se si do ti referohet ky segment vetvetes, si 4 apo si 15? Pasi ekziston një
kopje fizike e nënprogramit për rrënjën katrore ai duhet ti referohet vetes me të njejtin numër për
të dy proceset. Me rritjen e numrit të shfrytëzuesve që e përdorin të njejtin segment zgjedhja e
numrit adekuat vështirësohet.
Segmentet e të dhënave që vetëm mund të lexohen (pa tregues) mund të përdoren si
segmente me numra të ndryshëm si edhe segmentet e kodit që nuk i referohen vetes direkt, por
vetëm në mënyrë indirekte.

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.

5.8 Sistemet e kombinuara

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.

5.8.1 Faqëzimi i segmentuar

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.

5.8.2 Segmentimi i 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

Në këtë kapitull do të vazhdojmë shqyrtimin e proceseve, të dhënat fillestare për të cilët i


kemi dhënë në kapitujt paraprak. Do të shqyrtojmë posaçërisht qështjen e konkurencës në kuadër
të vetë procesit dhe mes proceseve.

7.1 Grafet e përparësisë

Të shikojmë segmentin vijues të programit që kryen disa operacione të thjeshta


aritmetikore.

a:=x+y;
b:=z+1;
c:=a-b;
w:=c+1;

Të supozojmë se disa nga këto instruksione dëshirojmë ti ekzekutojmë në mënyrë konkurente.


Kompjuteri jonë mund të ketë më shumë njësi te njejta funksionale, p.sh. më shumë mbledhës ose
më shumë shumëzues, ndoshta edhe më shumë procesorë. "Mbledhja" dhe "zbritja" mund të jenë
operacione që kryhen mbi matrica ose vektorë, ose mbi bashkësi shumë të mëdha (unioni dhe
prerja), ose mbi datoteka (bashkimi dhe ndarja). Nëse kemi më shumë procesorë disa instruksione
do të mund ti ekzekutonim njëkohësisht (në mënyrë konkurente) me instruksionet tjera duke
zvogluar kohën e gjithmbarshme të ekzekutimit.
Është e qartë se p.sh. instruksionin c:=a-b nuk do të mund ta ekzekutojmë para se a-së
dhe b-së ti kemi dhënë vlerat. Poashtu, w:=c+1 nuk mund të llogaritet para se të jetë llogaritur
vlera e c-ës. Në anën tjetër, a:=x+y dhe b:=z+1 mund të ekzekutohet njëkohësisht, pasi nuk varen
njëra nga tjetra.
Me këtë shembull deshëm të tregojmë se në kuadër të një programi kemi kufizime që
rrjedhin nga përparësia e ekzekutimit të instruksioneve të ndryshme. Në vazhdim do të japim
përshkrimin formal të kësaj që thamë.

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ë

Fig.7.2 Grafi i përparësisë me cikle

7.1.2 Kushtet e konkurencës

Do të na intereson të dijmë se kur dy instruksione mund të ekzekutohen në mënyrë


konkurente dhe të japin rezultat të njejtë. Para se të japim përgjigje në këtë pyetje, të shënojmë:
- R(Si) = {a1, a2, ..., am}, do të jetë bashkësia e leximit (ang. read set), në të cilën bëjnë

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}

Për instruksionin w:=c+1 bashkësitë e leximit dhe shkruarjes janë:

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:

W(S2) ∩ R(S3) = {b}.

7.2 Specifikacionet

Grafet e përparësisë janë mjet i vlershëm në caktimin e përparësisë së pjesëve të ndryshme


të llogaritjes. Mirëpo, grafet e përparësisë nuk mund të shfrytëzohen si pjesë e gjuhës
programore. Programerëve duhet ofruar tjera mjete që të realizojnë relacionet e përparësisë mes
instruksioneve të ndryshme në program.

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.

Fig.7.3 Grafi i përparësisë për konstruksionin fork

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.

Fig.7.4 Grafi përparësisë për konstruksionin join

Të marrim përsëri në shqyrtim programin e parë. Që të lejojmë ekzekutimin konkurent të


dy instruksioneve të para, programin mund ta rishkruajmë kështu:
count:=2;
fork L1;
a:=x+y;
go to L2;
L1: b:=z+1;
L2: join count;

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.

7.2.2 Instruksioni konkurent

Një konstruksion i gjuhëve të larta programore për specifikimin e konkurencës është


instruksioni parbegin/parend i dhënë nga Dijkstra [1965] që ka formën:

parbegin S1; S2; ...; Sn parend;

Ç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.

Fig.7.5 Grafi i përparësisë për instruksioni konkurent

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;

Grafit të përparësisë të dhënë me figurën 7.1 i përgjigjet programi vijues:

S1;

127
parbegin
S3;
begin
S2;
S4;
parbegin
S5;
S6;
parend;
end;
parend;
S7;

Programin që kopjon një datotekë në tjetrën do ta shkruajmë si:

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

Fatkeqësisht, instruksioni konkurent nuk është i mjaftueshëm për modelimin e të gjitha


grafeve të përparësisë. Do të bëjmë një ndërrim në grafin e përparësisë së figurës 7.1 për të fituar
grafin nga figura 7.6. Dega e grafit nga S3 në S7 është larguar pasi shtimi i degës prej S3 në S6 e ka
bërë të tepërt. Grafi i ri nuk ka program korespondues që do të mund të shkruhej duke përdorë
instruksionin konkurent.
Në pikëpamje të modelimit të grafeve të përparësisë, konstruksioni fork/join është më i
fuqishëm se instruksioni konkurent. Grafi i përparësisë nga figura 7.6, i cili nuk ka program
gjegjës që përmban instruksionin konkurent, e ka programin që i përgjigjet, të shkruar me
instruksionet fork dhe join.

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.

Fig.7.6 Grafi i përparësisë për të cilin nuk ekziston instruksioni konkurent

7.3 Rishqyrtim i konceptit të procesit

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.

7.3.1 Gjendja e procesit

Procesi sekuencial mund të jetë në njërën nga këto katër gjendje:


- Ekzekutohet. Instruksionet janë duke u ekzekutuar.
- I bllokuar. Procesi është duke pritur të paraqitet një ngjarje (p.sh. përfundimi i
operacionit të hyrje-daljes).
- I gatshëm. procesi pret ti jepet procesorit.
- I ngujuar (ang. deadlocked). Procesi është duke pritur për ndonjë ngjarje që nuk do të
ndodh kurr.
Diagrami i gjendjeve që i përgjigjet këtyre katër gjendjeve është dhënë në figurën 7.7. Në
esencë është fjala për diagram të njejtë si ai i figurës 4.7, por i është shtuar edhe gjendja e ngujuar.

Fig.7.7 Diagrami i gjendjes së procesit

7.3.2 Raporti ndaj grafeve të përparësisë

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ë:

parbegin S1, S2, ..., Sn parend;

një instruksion i përgjithshëm. Ai mund të simulohet me:

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ë.

7.4 Hierarkia e proceseve

Do t'ia kushtojmë në vazhdim vëmendjen raportit mes proceseve dhe llojeve të


operacioneve që mund të kryhen në lidhje me një proces. Do të definojmë një paraqitje të re të
llogaritjes që do ta quajmë graf i procesit.

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.

7.4.1 Operacionet mbi procese

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

parbegin S1, S2, ..., Sn parend;

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

Procesi përfundon kur të përfundon ekzekutimin e instruksionit të fundit. Mirëpo,


ekzistojnë edhe rrethana tjera kur mund të përfundojë procesi. Procesi mund të shkaktojë
përfundimin e një procesi tjetër duke ekzekutuar komandën:

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

krijon procesin e ri (që ekzekutohet nga L) identiteti i të cilit do të ruhet në id.


Prindi mund ta përfundojë ekzekutimin e njërit prej fëmijve të tij për arsye të ndryshme si:
a. Fëmija e ka tejkaluar kohën e përdorimit ose sasinë e resursit që i është dhënë.
b. Detyra që i është dhënë fëmijës nuk kërkohet më.
Që të caktohet (a) duhet të ekzistojë mekanizmi që ia lejon prindit inspektimin e gjendjes
së fëmijve.
Në shumë sisteme nuk është e lejuar që pas përfundimit të ekzekutimit të prindit në sistem
të ekzistojnë fëmijt e tij. Në sistemet e tilla, nëse përfundon procesi Pi (normalisht ose
abnormalisht), atëherë edhe të gjithë fëmijët e tij duhet të përfundohen. Këtë e quajmë përfundim
kaskadik (ang. cascading termination) dhe ky zakonisht inicohet nga sistemi operativ.

7.4.2 Proceset statike dhe dinamike

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.

7.5 Problemi i seksionit kritik

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.

type item = ...;


var buffer: array [0..n-1] of item;
in, out: 0..n-1;
nextp, nextc: item;
in:=0;

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;

Kodi për konsumuesin mund të modifikohet në këtë mënyrë:

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;

ku regjistri1 është regjistër lokal i procesorit. Ngjashëm, instruksioni counter:=counter-1


implementohet si:

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ë:

T0: prodhuesi execute regjistri1:=counter {register1=5}


T1: prodhuesi execute regjistri1:=regjistri1+1 {register1=6}
T2: konsumuesi execute regjistri2:=counter {register2=5}
T3: konsumuesi execute regjistri2:=regjistri2-1 {register2=4}
T4: prodhuesi execute counter:=regjistri1 {counter=6}
T5: konsumuesi execute counter:=regjistri2 {counter=4}

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.

7.5.1 Definicioni i problemit

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.

7.5.3 Zgjidhja softverike për dy procese

Do të shkojmë hap pas hapi në shpjegimin e zhvillimit të algoritmeve për sigurimin e


përjashtimit reciprok. Së pari do të merremi me vetëm dy procese, proceset P0 dhe P1. Më vonë
do të trajtojmë edhe problemin më të përgjithshëm të n proceseve. Struktura gjenerale e
problemit është:

begin
deklarimi i variablave të përbashkëta
parbegin

137
P0;
P1;
parend;
end.

Kur ta prezentojmë algoritmin do të definojmë vetëm variablat e përbashkëta dhe do ta


përshkruajmë procesin Pi. Me Pj do ta shenojmë procesin tjetër, j=1-i.
Më poshtë do të japim strukturën e përgjithshme të procesit Pi. Seksioni hyrës dhe dalës
janë të dalluara për të potencuar rëndësinë e kësaj pjese të kodit.

repeat
seksioni hyrës;

seksioni kritik;

seksioni dalës;

seksioni mbetës;

until false;

Algoritmi 1

Në tentimin e parë do të lejojmë që proceset të ndajnë variablën e përbashkët turn (shq.


rradha), që do të inicializohet në vlerën 0 (ose 1). Nëse turn = 1, atëherë procesit Pi i është lejuar
të ekzekutojë kodin nga seksioni i tij kritik.

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

Problemi me algoritmin 1 është se ai harron ta mbajë në mend gjendjen e secilit proces,


por e mban në mend vetëm cilit proces i është lejuar hyrja në seksionin kritik. Për të zgjedhur këtë
problem, do ta zëvendsojmë variablën turn me fushën (vektorin) vijuese:

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:

T0: P0 hyn në instruksionin while dhe e gjen flag[1]=false


T1: P1 hyn në instruksionin while dhe e gjen flag[0]=false
T2: P1 vendos flag[1]=true dhe hyn në seksionin kritik
T3: P0 vendos flag[0]=true dhe hyn në seksionin kritik

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

Problemi i algoritmit 2 është se procesi Pi ka ardhë në konkludim për gjendjen e procesit


Pj para se Pj të ketë fituar rastin ta ndërroj gjendjen e variablës flag[j]. Mund të tentojmë ta
korigjojmë këtë problem. Si në algoritmin 2, do ta mbajmë edhe më tutje fushën flag. Këtë herë
vendosja e flag[i] = true tregon vetëm se Pi dëshiron të hyj në seksionin kritik.

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:

T0: P0 evendos flag[0]=true


T1: P1 evendos flag[1]=true

Tani P0 dhe P1, janë duke u sjellur pa ia nda, secili në unazën e vet while.

Algoritmi 4

Siç mund të vërehet, nuk ka zgjidhje të thjeshtë të problemit të seksionit kritik. Me


korigjimin e një gabimi paraqitet një gabim tjetër. Do të japim më në fund zgjidhjen e saktë të
këtij problemi që e dha Peterson [1981]. Kjo zgjidhje është në esencë kombimin i algoritmit 3 dhe
një modifikimi të vogël të algoritmit 1.
Proceset ndajnë dy variabla të përbashkëta:

var flag: array [0..1] of boolean;


turn: 0..1;

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).

7.5.3 Zgjidhjet softverike për N procese

Në vazhdim do të tregojmë algoritmin që zgjedh problemin e seksionit kritik për n


procese. Autor i algoritmit 5 janë Eisenberg dhe McGuire [1972], ndërsa i algoritmit 6 është
Lamport [1974].

Algoritmi 5

Strukturat e përbashkëtat të të dhënave janë:

var flag: array [0..n-1] of (idle, want_in, in_cs);


turn: 0..n-1;

(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;

Për të vërtetuar zgjidhjen e Eisenbergut dhe McGuireit na duhet edhenjëherë 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ë (a) do të cekim se secili Pi hyn në seksionin e vet kritik vetëm
nëse flag[j]<>in_cs për çdo j<>i. Pasi vetëm Pi mund ta setojë flag[i]=in_cs dhe pasi që Pi e
kontrollon flag[j] vetëm derisa vlen flag[i]=in_cs, rrjedh se kondita (a) vlen.
Për të vërtetuar cilësinë (b) do të vëmë në dukje se vlera e turn mund të modifikohet
vetëm në rastin kur procesi hyn në seksionin e tij kritik dhe vetëm kur del prej tij. Pra, nëse asnjë
proces nuk është në seksionin kritik ose duke dalë nga ai, vlera e turn do të mbetet e pandryshuar.
Në seksionin kritik do të hyjë procesi i parë pretendues nga rreshti ciklik (i, i+1, ..., n-1, 0, ..., j-
1).
Për të vërtetuar cilësinë (c) do të vemi në dukje se kur procesi largohet nga seksioni
kritik, ai duhet të përcaktojë si pasues unik procesin e parë pretendues nga rreshti ciklik, duke
siguruar se cilido proces që dëshiron të hyjë në seksionin e vet kritik do ta bëjë këtë brenda n-1
rradhëve.

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ë:

var choosing: array [0..n-1] of boolean;


number: array [0..n-1] of integer;

(ang. choosing, shq. që zgjedhë).


Në fillim këto struktura të të dhënave janë të inicializuara në false dhe 0, respektivisht. Për
lehtësim do ta definojmë këtë shënim:
- (a,b)<(c,d) nëse a<c ose nëse a=c dhe b<d.
- max(a0, ..., an-1) është numër, k, i tillë që k>=ai për i=0, ..., n-1.
Struktura e procesit Pi është:

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;

Që të vërtetojmë algoritmin e furrës, duhet së pari të tregojmë se nëse Pi është në


seksionin e vet kritik dhe Pk (k<>i) e ka zgjedhë numrin e vet (number[k]<>0), atëherë (num­
ber[i],i) < (number[k],k). Nuk do të japim vazhdimin e vërtetimit.
Do të tregojmë se përjashtimi reciprok është i siguruar. Të marrim se Pi është në
seksionin e vet kritik dhe se Pk është duke provuar të hyjë në seksionin e vet kritik. Kur Pk e
ekzekuton instruksionin e dytë while për j=i do të gjen se:

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).

7.5.4 Zgjidhjet hardverike

Shumë kompjuterë kanë instruksione speciale hardverike që mundësojnë testimin dhe


ndërrimin e përmbajtjes së fjalës ose mundësojnë shkëmbimin (ang. swap, shq zëvendsimi,
shkëmbimi) e përmbajtjes së dy fjalëve, brenda një ciklusi memorik. Këto instruksione speciale
mund të përdoren për zgjidhjen e problemit të seksionit kritik. Do të japim konceptin themelor që
rri pas këtyre llojeve të instruksioneve, duke dhënë në vazhdim instruksionin Test_and_set
(testoje dhe vendose):

function Test_and_set (var target: boolean): boolean;


begin
Test_and_set:=target;
target:=true;
end;

(ang. target, shq. caku) dhe instruksionin Swap (shkëmbeje):

procedure Swap (var a, b: boolean);


var temp: boolean;
begin
temp:=a;
a:=b;
b:=temp;
end;

(Implementimi konkret mund të ndryshojë, që do të varet nga makina konkrete).


Karakteristikë e rëndësishme e këtyre instruksioneve është se këto instruksione
ekzekutohen atomikisht; do të thotë brenda një cikli memorik. Pra, nëse dy instruksione
Test_and_set ose Swap ekzekutohen njëkohësisht (secila në procesor tjetër), ato do të
ekezekutohen sekuencialisht me një renditje arbitrare. Nëse makina përkrah instruksionin
Test_and_set, atëherë përjashtimi reciprok mund të realizohet me deklarimin e variablës së Boolit
lock (shq. dryni) të inicializuar në false.

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;

Algoritmet e prezentuara nuk kënaqin kushtin për pritje të kufizuar. Që ky kusht të


kënaqet, duhet përdorë variabla shtesë. Do të japim në vazhdim algoritmin e dhënë nga Burns
[1978] që përdorë instruksionin Test_and_set, dhe që kënaq të gjitha kërkesat në lidhje me
seksionin kritik.
Strukturat e përbashkëtat të të dhënave janë:

var waiting: array [0..n-1] of boolean


lock: boolean

(ang. waiting, shq. që është duke pritur).


Këto struktura të të dhënave inicializohen në false.
Struktura e procesit Pi është:

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

Për probleme më komplekse është vështirë të gjeneralizojmë zgjidhjen për përjashtim


reciprok. Për të tejkaluar këtë problem Dijkstra prezentoi një vegël të re sinkronizuese të quajtur
semafor. Semafori S është variabël integer të cilës përveç gjatë inicializimit, mund ti qasemi
vetëm përmes dy operacioneve standarde atomike: P dhe V. Definicioni klasik i operacioneve P
dhe V është:

P(S): while S <= 0 do skip;


S:=S-1;

V(S): S:=S+1;

Modifikimi i vlerës integer të semaforit në operacionet P dhe V bëhet pandashëm. Kjo do


të thotë se kur një proces e ndërron vlerën e semaforit, asnjë proces tjetër nuk mundet në mënyrë
simultane të modifikojë vlerën e të njejtit semafor. Në rastin e P(S), testimi i vlerës së S (a është S
<= 0) dhe modi-fikimi i mundshëm (S:= S - 1) duhet poashtu të ekzekutohet pa ndërprerje. Të
shohim së pari si mund të përdoren semaforët.

7.6.1 Përdorimi

Semaforët mund ti përdorim në zgjidhjen e problemit të seksionit kritik të n proceseve. N


procese e ndajnë të njejtin semafor, të quajtur mutex (shkurtesë për mutual exclusion), të inicializ­
uar në vlerën 1. Çdo proces Pi është i organizuar në këtë mënyrë:

repeat
P(mutex);

146
seksioni kritik;

V(mutex);

seksioni mbetës;

until false;

Semaforët mund të përdoren edhe në zgjidhjen e problemeve të ndryshme sinkronizuese.


Të shikojmë dy procese konkurente: P1 me instruksionin S1 dhe P2 me instruksionin S2. Të
supozojmë se S2 duhet të ekzekutohet vetëm pas përfundimit të S1. Kjo skemë mund të
implementohet duke lejuar proceset P1 dhe P2 të ndajnë semaforin e përbashkët synch, të
inicializuar në 0 dhe me insertimin e instruksioneve

S1;
V(synch);

në procesin P1 dhe instruksioneve

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.

type semaphore = record


value: integer;
L: list of process;
end;

Ç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:

P(S): S.value := S.value - 1;


if S.value < 0
then begin
shtoje këtë proces në S.L;
block;
end;

V(S): S.value := S.value + 1;


if S.value <= 0
then begin
largoje një proces nga S.L;
wakeup(P);
end;

Operacioni block e suspendon procesin që e thërret operacionin block. Operacioni wakeup(p)


vazhdon ekzekutimin e procesit të bllokuar P. Këto dy operacionin janë pjesë e sistemit operativ

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.

7.7 Problemet klasike të koordinimit të proceseve

Do të japim në vazhdim disa probleme klasike të koordinimit të proceseve. Këto


probleme janë të rëndësishme për arsye se mbulojnë një klasë të madhe të problemeve të
kontrollit të konkurencës. Këto probleme merren për testimin e cilësdo skemë të re sinkronizuese.
Në zgjidhjet e dhëna janë përdorë semaforët.

7.7.1 Problemi i numrit të kufizuar të baferëve

Problemin e numrit të kufizuar të baferëve e kemi dhënë më parë (7.5) e tani do ta


paraqesim strukturën e përgjithshme të kësaj skeme, pa u thelluar në çfarëdo implemetimi

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.

type item = ...;


var buffer = ...;
full, empty, mutex: semaphore;
nextp, nextc: item;
begin
full := 0
empty := n;
mutex := 1;

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.

7.7.2 Problemi i lexuesve dhe shkrimtarëve

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:

var mutex, wrt: semaphore;


readcount: integer;

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.

7.7.3 Problemi i filozofëve

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ë:

var chopstick: array [0..4] of semaphore;

(ë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.

Fig.7.9 Problemi i filozofëve

7.8 Komunikimi mes proceseve

Problemet që i kemi përshkruar janë prezentuar si probleme të sinkronizimit. Por në


kuptim më të gjërë, ato paraqesin raste të thjeshta të një problemi më të madh të komunikimit të
proceseve që dëshirojnë të bashkëpunojnë. Ekzistojnë dy skema komplementare të komunikimit:
memoria e përbashkët (ang. shared memory) dhe sistemet e porosive (ang. message systems).
Sistemet me memorie të përbashkët kërkojnë nga proceset komunikuese të ndajnë disa
variabla të përbashkëta. Pritet që proceset do të shkëmbejnë informatat përmes shfrytëzimit të
këtyre variablave të përbashkëta. Për shembull skema e përdorur për problemin e numrit të
kufizuar të baferëve (7.5) mund të shërbejë për këtë qëllim. Në skemën që përdorë memorien e
përbashkët përgjegjësia për sigurimin e komunikimit i takon programerit të aplikacionit; sistemit
operativ i takon vetëm të sigojë memorien e përbashkët. Sistemi i porosive i lejon proceset të
shkëmbejnë porosi. Në këtë skemë përgjegjësia për sigurimin e komunikimit i mbetet sistemit
operativ.
Këto dy skema nuk përjashtohen reciprokisht dhe do të mund të përdoreshin në të njejtin
sistem operativ. Në vazhdim do të koncentrohemi më shumë në sistemet e porosive, pasi këto të
tjerat janë më shumë të orientuara kah aplikacionet. Do të marrim parasysh vetëm sistemet me
procese hapësira adresore logjike e të cilëve është e ndarë.
Funksioni i sistemit të porosive është të lejojë proceset të komunikojnë mes veti pa
përdorim të variablave të përbashkëta. Zakonisht, sistemi për komunikim ndërmjet proceseve
ofron dy operacione: send(message) (shq. dërgoje(porosia)) dhe receive(message) (shq.
pranoje(porosia)).

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

Do të ndalemi në tri qështjet e para që kanë të bëjnë me implementimin logjik të lidhjes.

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):

send (P, message). Dërgoja message procesit P.


receive (Q, message). Pranoje message nga procesi Q.

Lidhja komunikuese në këtë skemë ka këto cilësi:


- Lidhja realizohet automatikisht mes çdo çifti të proceseve që donë të komunikojnë.
Proceset nevojitet vetëm të dijnë identitetin e njëri tjetrit.
- Lidhja ka të bëjë me dy procese.
- Mes çdo çifti të proceseve që komunikojnë ekziston një lidhje.
- Lidhja është dykahëshe.
Për shëmbull, problemi i prodhuesve dhe konsumuesve mund të kodohet në këtë mënyrë:

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;

Nëse ky shembull trajtohet si skema me numër të kufizuar të baferëve, atëherë madhësia e


baferëve është e barabartë me kapacitetin e lidhjes komunikuese.
Kjo skemë tregon simetri në adresim. Me qëllim të komunikimit edhe dërguesi edhe
pranuesi duhet të emrojnë njëri tjetrin. Një variantë e kësaj skeme shfrytëzon asimetrinë në
adresim. Vetëm dërguesi e emron pranuesin; nga pranuesi nuk kërkohet të emrojë dërguesin. Në
këtë skemë primitivet send dhe receive janë të definuara si:

- send (P, message). Dërgoja message procesit P.


- receive (id, message). Pranoje message nga cilido proces;
id e ka emrin e procesit me të cilin është krijuar komunikimi.
Dobësi e të dy skemave (simetrike ose asimetrike) është modulariteti i kufizuar i
definicioneve rezultuese të proceseve. Ndërrimi i emrit të procesit, mund të bën të nevojshëm
shqyrtimin e të gjitha definicioneve të procesit. Me këtë rast duhet gjetur të gjitha referencat e
bëra emrit të vjetër të procesit me qëllim të zëvendsimit me emër të ri. Ky rast paraqitet me rastin
e kompajlimit të veçantë të moduleve programore.

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:

- send (A, message). Dërgoje message në kutinë A.


- receive (A, message). Pranoje message nga kutia A.

Në këtë skemë, lidhja komunikuese ka këto cilësi:


- Lidhja mes proceseve realizohet vetëm nëse çifti i proceseve ka kutinë e përbashkët.
- Lidhja mund të të jetë e shoqëruar me më shumë se dy procese.

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

Do të shqyrtojmë dy qështje tjera që kanë të bëjnë me implementimin logjik të lidhjes:


kapacitetin dhe vetitë e porosive.

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:

send (Q, message);


receive (Q, message);

e procesi Q do të ekzekutojë:

receive (P, message);


send (P, "vërtetimin");

Porositë

Porositë që i dërgojnë proceset mund të jenë:


- Të madhësisë fikse.
- Të madhësisë variabile.
- Porosi të tipizuara.
Nëse mund të dërgohen vetëm porosi të madhësisë fikse, implementimi fizik është i
thjeshtë. Mirëpo, ky kufizim e bën programimin më të vështirë. Porositë me gjatësi të
ndryshueshme e bëjmë implementimin fizik më kompleks, por thjeshtojnë programimin.
Në rastin e fundit me bashkangjitjen e tipit secilës kuti, e kufizojmë përdorimin vetëm në
komunikim indirekt. Porositë e dërguara dhe të pranuara janë të obliguara të jenë të tipit të
caktuar. Kjo është posaçërisht e mirëseardhur për kutitë e deklaruara në gjuhën programore që ka
kontroll rigoroz të tipit të të dhënave. Për shembull, kutia për ruajtjen e n elementeve për
problemin e prodhuesve dhe konsumuesve mund të deklarohet si:

m: mailbox[n] of item;

157
Rastet speciale

Janë dy raste speciale që nuk mund të klasifikohen drejtpërdrejt në asnjërën nga


kategoritë e përmendura.
- Procesi që e dërgon porosinë nuk do të suspendohet asnjëherë. Mirëpo, nëse pranuesi
nuk e ka pranuar porosinë para se procesi i dërguesit ta dërgon porosinë e dytë, porosia e parë do
të humbet. Kjo skemë është më shumë e bazuar në implementimin fizik të "dërgimit të referencës"
se sa "dërgimit të kopjes". Përparësia e kësaj skeme është se porositë e mëdhaja nuk kanë nevojë
të kopjohen më shumë se njëherë. Mirëpo, detyra e programimit të sistemit të tillë është më e
vështirë. Proceset duhet të sinkronizohen në mënyrë eksplicite, duhet të sigurohemi se porositë
nuk humben dhe se dërguesi dhe pranuesi nuk manipulojnë njëkohësisht me baferin e porosive.
- Procesi që dërgon porosinë suspendohet derisa ta fiton përgjegjen. Në sistemin operativ
Thoth që përdorë këtë skemë, porositë janë të madhësisë fikse (8 fjalë). Procesi P që e dërgon
porosinë është i bllokuar derisa procesi pranues ta pranon porosinë dhe ta dërgon përgjegjen me
anë të primitivit reply (P, message). Porosia e përgjegjes e mbishkruan porosinë origjinale në
bafer. E vetmja diferencë mes primitiveve send dhe reply është se send shkakton bllokimin e
procesit dërgues, ndërsa reply lejon të dy proceseve, të pranuesit dhe dërguesit, të vazhdojnë
mënjëherë me ekzekutimin e tyre.

7.6.3 Konditat e jashtëzakonshme

Sistemi i porosive është posaçërisht i përdorshëm për rrethinën e distribuar, ku proceset


mund të ndodhen në makina të ndryshme. Në kësi rrethine gjasa e paraqitjes së gabimit gjatë
komunikimit është shumë më e madhe se në rrethinën me një makinë. Në rrethinën njëprocesorike
porositë janë zakonisht të implementuara në memorien e përbashkët. Nëse ngjan ndonjë defekt i
tërë sistemi bie. Në rrethinënë e distribuar porositë zakonisht manipulohen nga linjat
komunikuese, dhe rënja e një makine nuk shkakton rënjën e domosdoshme të tërë sistemit.
Kur defekti të paraqitet si në rrethinën e centralizuar si në ate të distribuar, duhet të bëhet
njëfarë riparimi nga gabimi (e njohur si ang. exception condition handling shq. trajtim i rastit të
jashtëzakonshëm). Do të tregojmë disa kondita të jashtëzakonshme të cilat sistemi duhet ti
trajtojë në kontekstin e shkëmbimit të porosive.
1. Procesi pranues P mund të jetë duke pritur porosinë nga procesi Q i cili ka përfunduar.
Nëse asgjë nuk ndërmerret, procesi P do të jetë i bllokuar përgjithmonë. Në këtë rast sistemi
mund ta përfundojë procesin P ose ti lajmëroj se procesi Q ka përfunduar.
2. Procesi P mund ti dërgojë porosi procesit Q që ka përfunduar. Në skemën e baferimit
automatik asgjë s'do të dëmtohet; procesi P do të vazhdojë ekzekutimin. Nëse P ka nevojë të dijë
se porosia e tij është përpunuar nga Q, ai duhet të ketë kodin e posaçëm për vërtetimin e
pranimit. Në rastin kur s'ka baferim, P do të bllokohet përgjithmonë. Si në rastin (1), sistemi
mund ta përfundojë P ose ta lajmëroj se Q ka përfunduar.

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

You might also like