პარალელური დაპროგრამება

პარალერული დაპროგრამება

პარალელური დაპროგრამება თანამედროვე დაპროგრამების ერთ-ერთი მნიშვნელოვანი შემადგენელი ნაწილია. ვინაიდან ის გარკვეულწილად ითვალისწინებს განსაკუთრებულ სიტუაციებს (გამონაკლისებს), ამიტომ აღნიშნული საკითხის განხილვა  მიზანშეწონილად ჩავთვალეთ.

 განსაკუთრებული სიტუაციების (გამონაკლისების) დამუშავება გამონაკლისი არასტანდარტული სიტუაციაა, რომელიც კოდის შესრულების დროს წარმოიქმნება. სხვა სიტყვებით, რომ ვთქვათ, გამონაკლისი შეცდომაა, რომელიც პროგრამის შესრულების დროს იჩენს თავს. დაპროგრამების ენებში, სადაც გამონაკლისების, ანუ განსაკუთრებული სიტუაციების დამუშავება ავტომატურად არ ხდება, შეცდომები „ხელით“ უნდა შესწორდეს პროგრამისტის მიერ, რაც საკმაოდ დამღლელი და შრომატევადი პროცესია. გამონაკლისების დამუშავების თვალსაზრისით, Java ამ პრობლემებისგან გვათავისუფლებს და მათი მართვა ობიექტზე ორიენტირებულ სამყაროში გადააქვს.

 

განსაკუთრებული სიტუაციების დამუშავების საფუძვლები

Java–ში გამონაკლისი არის ობიექტი, რომელიც იმ გამონაკლის (შეცდომითი ხასიათის) სიტუაციას აღწერს, რაც პროგრამული კოდის ამა თუ იმ ფრაგმენტში წარმოიქმნება. ასეთი სიტუაციის შექმნის დროს, შეცდომის გამომწვევ მეთოდში იქმნება და გადაიცემა ობიექტი, რომელიც გამონაკლისს წარმოადგენს. ასეთ შემთხვევაში, მეთოდი ან თავად, დამოუკიდებლად ახდენს გამონაკლისის დამუშავებას ან უბრალოდ გაატრებს მას. ორივე შემთხვევაში, გამონაკლისი მაინც იქნება გარკვეულ დროში აღმოჩენილი და დამუშავებული.

განსაკუთრებული სიტუაციების დამუშავება Java-ში ხუთი საკვანძო სიტყვით იმართება: try, catch, throw, throws  და finally.  მათი მუშაობის ზოგადი პრინციპი შემდეგია. პროგრამის ოპერატორები, რომელთა შემოწმება გვსურს გამონაკლისზე, თავსდება try ბლოკში. თუ აღნიშნულ ბლოკში ადგილი აქვს განსაკუთრებულ სიტუაციას, ის გამონაკლისის სახით იქმნება და გადაიცემა. ჩვენს პროგრამულ კოდს შეუძლია ამ გამონაკლისის დაჭერა (catch ბლოკის გამოყენებით) და გარკვეული საშუალებით დამუშავება. სისტემური გამონაკლისები ავტომატურად გადაეცემა Java-ს შესრულების დროის სისტემას, ხოლო გამონაკლისის „ხელით“ გადასაცემად throw საკვანძო სიტყვა გამოიყენება. ნებისმიერი გამონაკლისი, რომელიც იქმნება და გადაიცემა მეთოდში, მის ინტერფეისში უნდა იქნას მითითებული throws  საკვანძო სიტყვის გამოყენებით. ნებისმიერი კოდი, რომელიც აუცილებლად უნდა შესრულდეს try ბლოკის დასრულების შემდეგ, თავსდება finally ბლოკში.

ქვემოთ წარმოდგენილია განსაკუთრებული სიტუაციების (გამონაკლისების) დამუშავების

ბლოკის ზოგადი ფორმა:

try {
// კოდის ბლოკი, რომელშიც გამონაკლისი მოწმდება
}
catch(გამონაკლისის_ტიპი1 exOb )
{
  //გამონაკლისის_ტიპი1 ტიპის გამონაკლისების დამუშავება
}
catch(გამონაკლისის_ტიპი2 exOb )
{
  //გამონაკლისის_ტიპი2 ტიპის გამონაკლისების დამუშავება
}
//…
finally {
// კოდის ბლოკი, რომელიც try ბლოკის დასრულების შემდეგ უნდა შესრულდეს
}

 

აქ გამონაკლისის_ტიპი–ს ქვეშ მიმდინარე გამონკლისის ტიპი იგულისხმება.

გვინდა აღვნიშნოთ, რომ JDK7-ის კომპლექტში დამატებულია try ოპერატორის ახალი ფორმა, რომელიც რესურსების ავტომატურ მართვას უზრუნველყოფს. ამ ფორმას try–რესურსებით ეწოდება და მას ფაილებთან დაკავშირებულ შემდეგ თავებში განვიხილავთ, რადგან ფაილები ყველაზე ხშირად გამოყენებად რესურსებს წარმოადგენს.

 

გამონაკლისების ტიპები

გამონაკლისთა ყველა ტიპი Trowable ჩადგმული კლასის ქვეკლასს წარმოადგენს. ანუ, იგი

გამონაკლისთა კლასების იერარქიის ყველაზე მაღალ საფეხურზეა (მწვერვალზეა) განთავსებული. უშუალოდ Trowable კლასის ქვეკლასად ორი კლასი მოიაზრება, რომლებიც ყველა გამონაკლის სიტუაციას ორ ცალკეულ შტოდ ყოფს. ერთ შტოს Exception კლასი „უდგას სათავეში“. ეს კლასი იმ გამონაკლისი პირობებისთვის გამოიყენება, რომლებიც სამომხმარებლო პროგრამამ უნდა დაიჭიროს. ეს ამავდროულად, არის კლასი, რომლისგანაც მემკვიდრეობით უნდა მივიღოთ საკუთარი ქვეკლასები გამონაკლისი სიტუაციების საკუთარი ტიპების შექმნის დროს. Exception კლასი შეიცავს მნიშვნელოვან ქვეკლასს სახელწოდებით RuntimeException. აღნიშნული ტიპის გამონაკლისი სიტუაციები ავტომატურად განისაზღვრება იმ პროგრამებისთვის, რომლებსაც ჩვენ ვწერთ, და მოიცავენ ისეთ შეცდომებს, როგორიცაა ნულზე გაყოფა და მასივების მცდარი ინდექსაცია.

მეორე შტო Error კლასიდან იწყება. ის იმ გამონაკლისებს განსაზღვრავს, რომელთა წარმოქმნას პროგრამების ნორმალური შესრულების დროს არ ველით. Error ტიპის გამონაკლისები თავად Java-ს დაპროგრამების გარემოში მიმდინარე შეცდომების აღმოსაჩენად გამოიყენება. ასეთი შეცდომის ნიმუშს სტეკის გადავსება წარმოადგენს. Error ტიპის გამონაკლისები, როგორც წესი, კატასტროფული სიტუაციების პასუხად წარმოიქმნება, რომელთა დამუშავება ჩვენი პროგრამების მიერ შეუძლებელია.

მანამდე, სანამ გაიგებდეთ, თუ როგორ დაამუშავოთ საკუთარ პორგრამებში გამონაკლისები, სასურველია, ნახოთ, თუ რა ხდება მაშინ, როცა მათ არ ამუშავებთ. ქვემოთ წარმოდგენილ მცირე ზომის პროგრამაში სპეციალურად არის დაშვებული ნულზე გაყოფის შეცდომა.

პროგრამის კომპიუტერული რეალიზაცია:

package exc; public class Excep1 {

public staticvoid main(String ars[]){

int d=0;

int  a=45/d;

}

როდესაც Java სისტემა ნულზე გაყოფის მცდელობას აღმოაჩენს, ის გამონაკლისი შემთხვევის ახალ ობიექტს ქმნის და შემდეგ მას გადასცემს. ეს უკანასკნელი Excep1 კლასის შესრულების შეწყვეტას ახდენს, რადგან როგორც კი გამონაკლისი სიტუაცია გადაიცემა, მას იჭერს გამონაკლისი სიტუაციების დამამუშავებელი, რომელმაც მას სასწრაფოდ რამე უნდა მოუხერხოს. მოცემულ მაგალითში ჩვენ ამ განსაკუთრებული სიტუაციის არანაირი საკუთარი დამამუშავებელი არ გამოგვიყენებია, შესაბამისად, იგი Java-ს სტანდარტულმა გადამამუშავებელმა დაიჭირა. ნებისმიერი განსაკუთრებული სიტუაცია, რომელსაც ჩვენი პროგრამა არ დაიჭერს, საბოლოდ Java-ს სტანდარტული დამამუშავებლის მიერ იქნება დაჭერილი და დამუშავებული. სტანდარტული დამამუშავებელი წარმოგვიდგენს სტრიქონს, რომელიც განსაკუთრებულ სიტუაციას აღწერს, გამოიტანს სტეკის ტრასირებას განსაკუთრებული სიტუაციის წარმოქმნის წერტილიდან და პროგრამის შესრულებას შეწყვეტს. სწორედ, ეს გამონაკლისი შემთხვევაა წარმოდგენილი ზემოთ ნაჩვენებ (პროგრამის შესრულების შედეგი) კოდში. ყურადღება მიაქციეთ იმ ფაქტს, რომ კლასის სახელი Excep1, main() მეთოდის სახელი, ფაილის სახელი Excep1.java და სტრიქონის ნომერი 5 სტეკის ტრასირებაშია ჩართული. ასევე, ყურადსაღებია ისიც, რომ გადაცემული გამონაკლისი სიტუაცია წარმოადგენს Exception კლასის ქვეკლასს სახელწოდებით ArithmeticException, რომელიც უფრო ზუსტად აღწერს წარმოქმნილი შეცდომის ტიპს.

სტეკის ტრასირება ყოველთვის გვიჩვენებს მეთოდების გამოძახების იმ თანმიმდევრობას,რომელმაც შეცდომამდე მიგვიყვანა.
ახლა ვნახოთ წინა პროგრამის მეორე ვერსია  რომელიც იგივე შეცდომას, ოღონდსხვა მეთოდში (და არა main() მეთოდში) წარმოგვიდგენს.

პროგრამის კომპიუტერული რეალიზაცია:

package exc; publicclass Excep1 { static void subroutine()
{
int d=0;
int a=45/d;
}
publicstatic void main(String ars[]){
Excep1.subroutine();
}
}

აქ უკვე გამოძახებათა მთელი სტეკია წარმოდგენილი. როგორც ხედავთ, ბოლო სტრიქონში

ნაჩვენებია main() მეთოდის სტრიქონი 8, რომელშიც ადგილი აქვს subroutine() მეთოდის გამოძახებას, რაც მე–5 სტრიქონში იწვევს შეცდომას. სტეკის ტრასირება პროგრამის გამართვის თვალსაზრისით, ძალზე მოსახერხებელია, რადგან ის სრულ თანმიმდევრობას გვიჩვენებს იმ გამოძახებებისა, რამაც შეცდომამდე მიგვიყვანა.

 

 

 try  და catch ბლოკების გამოყენება

მართალია, Java სისტემის გამონაკლისების სტანდარტული დამმუშავებელი პროგრამის გამართვის თვალსაზრისით საკმაოდ მოხერხებულია, მაგრამ როგორც წესი, მომხმარებელს თავად სურს საკუთარ პროგრამებში წარმოქმნილი განსაკუთრებული სიტუაციების დამუშავება. ეს უკანასკნელი ორ უპირატესობას გვაძლევს. პირველ რიგში, საშუალება გვაქვს შეცდომა გამოვასწოროთ, ხოლო მეორეს მხრივ, პროგრამის შესრულების ავტომატურ შეწყვეტას ადგილი აღარ აქვს. ცხადია, მომხმარებელთა უმრავლესობა ყოველთვის უკმაყოფილო იქნება, თუ ჩვენი პროგრამა გაჩერებას და სტეკის ტრასირებას შეუდგება შეცდომის ყოველი წარმოქმნის შემთხვევაში. თუმცა, ამ საკითხის გამოსწორება საკმაოდ მარტივადაა შესაძლებელი. ამისათვის საკმარისია, პროგრამული კოდის ის ფრაგმენტი, რომლის შემოწმებაც გვსურს, მოვათავსოთ try ბლოკში, რომლის შემდეგ catch კონსტრუქციას უნდა მივმართოთ, რომელიც განსაკუთრებული სიტუაციის ტიპს უთითებს. იმისათვის, რომ ვნახოთ, თუ რამდენად მარტივად კეთდება ეს ყოველივე, ქვემოთ წარმოდგენილ პროგრამაში try ბლოკი catch კონსტრუქციასთან ერთად არის ჩართული. ეს უკანასკნელი ArithmeticException ტიპის გამონაკლისის დამუშავებას ახდენს, რომელიც ნულზე გაყოფის მცდელობის შედეგად წარმოიქმნება.

პროგრამის კომპიუტერული რეალიზაცია:

package exc;publicclass Excep1 {
publicstaticvoidmain(String ars[]){
intd, a;
try{
//კოდის მონიტორინგის ბლოკი
d=0;
a=45/d;
System.out.println(“შედეგი არ გამოიტანება”);
}
catch(ArithmeticException e)
{
System.out.println(“0-ზე გაყოფა”);

}
               System.out.println(“catch ოპერატორის შემდეგ”);
}
}

ყურადღება მიაქციეთ იმ ფაქტს, რომ println() მეთოდი try ბლოკის შიგნით არასდროს შესრულდება. როგორც კი განსაკუთრებული სიტუაცია გადაიცემა, try ბლოკიდან მართვა catch ბლოკს გადაეცემა. ანუ, სტრიქონი: „შედეგი არ გამოიტანება“, კონსოლზე არ გამოისახება. catch ბლოკის შესრულების შემდეგ პროგრამაში მართვა try/ catch ბლოკის მომდევნო სტრიქონს გადაეცემა.

try და catch ოპერატორები ერთიან კვანძს შეადგენენ. catch ბლოკის მოქმედების არე არ ვრცელდება იმ ოპერატორებზე, რომლებიც try ოპერატორის წინაა განთავსებული. catch ოპერატორი ვერ იჭერს სხვა try ოპერატორის მიერ გადაცემულ განსაკუთრებულ სიტუაციას (გარდა ჩალაგებული try კონსტრუქციების შემთხვევებისა, რომელთაც მოგვიანებით განვიხილავთ). try ბლოკის მიერ დაცული ოპერატორები ფიგურულ ფრჩხილებში უნდა იქნეს მოთავსებული, ანუ ისინი ბლოკის შიგნით უნდა მდებარეობდეს. პროგრამის ცალკეულ ოპერატორზე try ოპერატორს ვერ გამოვიყენებთ.

სწორად აგებული catch ოპერატორების მიზანი განსაკუთრებული სიტუაციების აღმოფხვრა

და პროგრამის შესრულების გაგრძელებაა.

მაგალითი 1. შევადგინოთ პროგრამა, რომელშიც for ციკლის ყოველი იტერაცია ორ შემთხვევით რიცხვს იღებს. ეს ორი რიცხვი ერთმანეთზე იყოფა, ხოლო მიღებულ შედეგზე კი იყოფა რიცხვი 12345. საბოლოო შედეგი a ცვლადში თავსდება. თუ გაყოფის რომელიმე ოპერაცია ნულზე გაყოფის შეცდომას იწვევს, მას სათანადო ბლოკი იჭერს, a ცვლადის მნიშვნელობა ნულს უტოლდება და პროგრამის შესრულება გრძელდება.

პროგრამის კომპიუტერული რეალიზაცია:

package            exc; import java.util.Random;
public class Excep1 {     public static void main(String args[])
{
int a=0, b=0, c=0;
Random ob=new Random();
for(int i=0; i<10; i++){
try{
b=ob.nextInt();
c=ob.nextInt();

a=123435/(b/cსურ); . 7

}

შედეგი :       catch(ArithmeticException e){

System.out.println(“0-ზე გაყოფა”);

a=0;  //a-ს განულება და მუშაობის გაგრძელება

}

System.out.println(“a=” + a);}}}

გამონაკლისი სიტუაციების აღწერის გამოსახვა

Throwable კლასი ხელახლა განსაზღვრავს Object კლასში განსაზღვრულ toString() მეთოდს. ამგვარად, ის ახდენს იმ სტრიქონის დაბრუნებას, რომელიც გამონაკლისი სიტუაციის აღწერას შეიცავს. println() მეთოდის საშუალებით ჩვენ შეგვიძლია ამ აღწერის კონსოლზე გამოტანა. ამისათვის საკმარისია, println() მეთოდს არგუმენტის სახით გადავცეთ გამონაკლისი სიტუაცია. წინა პროგრამაში (მაგალითი 1) წარმოდგენილი catch ბლოკი შეგვიძლია შევცვალოთ. სახეშეცვლილი პროგრამის შესრულების შედეგი წარმოდგენილი, ხოლო მისი კომპიუტერული რეალიზაცია

package exc; import java.util.Random;
public class Excep1 {
public static void main(String args[]){
int a=0, b=0, c=0;                Random ob=new Random();
for(int i=0; i<10; i++){
try{
b=ob.nextInt();
c=ob.nextInt();
a=123435/(b/c);
}

catch(ArithmeticException სურ. 10 e)
{                            System.out.println(“განსაკუთრებული სიტუაცია” + e);
a=0;  //a-ს განულება და მუშაობის გაგრძელება

}

მრავალჯერადი    System. catch outოპერატორები.println(“a=”  + a);}}}

ავტ:ლელა გაჩეჩილაძე
ნონა ოთხოზორია