Лабораторын ажил №1

Хамгаалах эцсийн хугацаа: 3-р долоо хоног

Матриц үржүүлэх

M ширхэг мөртэй, K ширхэг баганатай A матрицыг, К ширхэг мөртэй N ширхэг баганатай В матрицаар үржүүлэхэд M ширхэг мөртэй, N ширхэг баганатай С матриц үүснэ. С матрицын i-р мөрийн j-р багана дээрх элементийн (Cij) утга нь А матрицын i-р мөрийн элементүүдийг В матрицийн j-р баганын элементүүдээр харгалзуулан үржүүлж нэмсэнтэй тэнцүү. Томъёог дараах байдлаар бичиж болно:

Жишээ нь хэрэв А матриц 3х2 хэмжээтэй, В матриц 2х3 хэмжээтэй байсан бол C3,1 элемент нь А3,1 х В1,1 болон А3,2 х В2,1 үржвэрүүдийн нийлбэртэй тэнцүү байна.

Энэ лабораторын ажлаар Ci,j элемент бүрийг нэг хуулбар процессоор тооцоолж олно. Ингэснээр бид M x N тооны хуулбар процесстой болно. Гол буюу эцэг хуулбар процесс нь А болон В матрицын анхны утгуудыг олгох ба А, В-гийн үржвэрийн утгыг хадгалах С матрицад хангалттай санах ой хуваарилж өгнө. Эдгээр матрицуудыг глобал байдлаар зарлах ба бүх хуулбар процессууд А, В, С матрицуудад хандаж чадах болно.

А болон В матрицыг анхны утгатайгаар доорх байдлаар зарлаж болно:

#define M 3

#define K 2

#define N 3

int A[M][K]={{1,4}, {2,5}, {3,6}};

int B[K][N]={{8,7,6}, {5,4,3}};

int C[M][N];

Мөн эдгээр утгуудыг файлаас уншдаг байж болно.

Хуулбар процесс бүрт параметр дамжуулах

Эцэг хуулбар процесс М х N ширхэг хуулбар процесс үүсгээд матрицын үржвэрийг тооцоолуулахын тулд тус бүрт нь i-р мөр болон j-р багана дахь утгуудыг дамжуулна. Энэ нь хуулбар процесс бүрт хоёр параметр дамжуулахыг шаардана. Pthreads болон Win32 – ыг ашиглах үед хамгийн амархан арга нь struct түлхүүр үгийг ашиглан бүтэц үүсгэх юм. Бүтцийн гишүүд нь i болон j болох ба бүтцийг доорх байдлаар зарлана:

/*хуулбар процессууд руу өгөгдөл дамжуулахад зориулсан бүтэц*/

struct v{

        int i; /*мөр*/

        int j; /*багана*/

};

Pthreads болон Win32-ын аль аль нь доор үзүүлсэнтэй төстэй байдлаар хуулбар процессуудаа үүсгэнэ:

/* M*N ширхэг хуулбар процесс үүсгэх */

for(i=0;i<M;i++){

        for(j=0;j<N;j++){

          struct v *data=(struct v *)malloc(sizeof(struct v));        

          data->i=i;

          data->j=j;

          /*Энд хуулбар процессыг үүсгэхдээ data-г параметр болгон дамжуулна*/

}

}

Заагч data-г pthread_create() функц руу (Pthreads) эсвэл CreateThread() функц руу (Win32) дамжуулах ба тэдгээр нь тусдаа хуулбар процесс байдлаар ажиллах функц рүү параметр байдлаар дамжуулна.

Java-гийн хуулбар процессуудын хооронд өгөгдөл дамжуулах нь Pthreads болон Win32-ынхоос ялгаатай. Нэг арга нь гол хуулбар процесс A, B, C матрицуудыг үүсгэж, анхны утгыг нь олгох юм. Дараа нь уг гол хуулбар процесс бусад хуулбар процессуудаа үүсгэн, тэдний байгуулагч функц тус бүрт гурван матрицыг, мөрийн дугаар i, баганын дугаар j-ийн хамт дамжуулна. Иймд хуулбар процесс нь дараах хэлбэртэй байна:

public class WorkThread implements Runnable{

        private int row;

        private int col;

        private int [] [] A;

        private int [] []  B;

        private int [] []  C;

        

        public WorkThread(int row, int col, int [] [] A, int [] [] B, int [] [] C){

                this.row=row;

                this.col=col;

                this.A=A;

                this.B=B;

                this.C=C;

}

public void run(){

        /*C[row][col] дахь матрицын үржвэрийг тооцоолох*/

}

}

Хуулбар процессуудыг дуусахыг хүлээх

Бүх хуулбар процесс дууссаны дараа гол хуулбар процесс С матриц дахь үржвэрийг гаргана. Иймд гол хуулбар процесс үржвэрийг хэвлэхийн тулд бусад бүх хуулбарыг ажиллаж дуусахыг хүлээнэ. Нэг хуулбар процесс нөгөөгөө дуусахыг хүлээх байдлыг хэд хэдэн аргаар хийж болно. 4.3-т (Section 4.3) Win32, Pthreads болон Java-гийн хуулбарын сангийн функцуудыг ашиглан яаж хүү процессыг дуусахыг хүлээх тухай тайлбарласан. Win32 нь WaitForSingleObject() функцтэй бол Pthreads болон Java нь харгалзан pthread_join() болон join() функцуудыг ашигладаг. Гэвч эдгээр програмын жишээнд эцэг процесс зөвхөн ганц хүү хуулбар процессоо дуусахыг хүлээж байгаа ба энэ лабораторын ажил нь олон хуулбар процессыг хүлээхийг шаардаж байгаа.

#define NUM_THREADS 10

/*нэгтгэх гэж байгаа хуулбар процессуудын хүснэгт*/

pthread_t workers[NUM_THREADS];

for(int i=0; i<NUM_THREADS; i++)

        pthread_join(workers[i], NULL);

Зураг 4.12 Арван хуулбар процессыг нэгтгэх Pthread код

4.3.2 – т нэг хуулбар процессыг дуусахыг хүлээдэг WaitForSingleObject() функцийг авч үзсэн. Win32 API – д мөн олон хуулбар процесс дуусахыг хүлээдэг WaitForMultipleObjects() функц байдаг. WaitForMultipleObjects() функц рүү дөрвөн параметр дамжуулагдана:

  1. Хүлээх объектийн тоо
  2. Объектуудын хүснэгтийн заагч
  3. Бүх объект руу дохио дамжуулагдсан эсэхийг заах флаг
  4. Хугацаа (эсвэл INFINITE)

final static int NUM_THREADS=10;

/*нэгтгэх гэж байгаа хуулбар процессуудын хүснэгт*/

Thread[] workers=new Thread[NUM_THREADS];

for(int i=0; i<NUM_THREADS; i++){

        try{

                workers[i].join();

}catch(InterruptedException ie){}

}

Зураг 4.13 Арван хуулбар процессыг нэгтгэх Java код

Жишээ нь, хэрэв THandles нь N хэмжээтэй Handle хуулбар процессын объектууд бол эцэг процесс хүү процессуудаа бүгдийг дуусахыг дараах функцийн дуудалтаар гүйцэтгэж болно:

WaitForMultipleObjects(N, THandles, TRUE, INFINITE);

Хэд хэдэн хуулбар процессын дуусахыг хүлээх өөр нэг хялбар арга нь Pthreads-ын pthread_join() болон Java-гийн join() функцээр нэгтгэх ажиллагааг for давталтан дотор хийх явдал юм. Жишээ нь та арван хуулбар процессыг Зураг 4.12-т үзүүлснээр Pthread код ашиглан нэгтгэж болно. Үүнтэй адил кодыг Java – гийн хуулбар процесс ашиглан бичсэнийг Зураг 4.13-т үзүүлэв.