Tải bản đầy đủ - 0 (trang)
X. Công nghệ tổ hợp

X. Công nghệ tổ hợp

Tải bản đầy đủ - 0trang

MPI_Comm_size(MPI_COMM_WORLD,&comm_size);

if (comm_size != 2) {printf("**** please run me with exactly 2 processes\n"); exit(-1); }

switch (Level)

{ case MPI_THREAD_SINGLE:

printf("thread level supported: MPI_THREAD_SINGLE\n");

break;

case MPI_THREAD_FUNNELED:

printf("thread level supported: MPI_THREAD_FUNNELED\n");

break;

case MPI_THREAD_SERIALIZED:

printf("thread level supported: MPI_THREAD_SERIALIZED\n");

break;

case MPI_THREAD_MULTIPLE:

printf("thread level supported: MPI_THREAD_MULTIPLE\n");

break;

default:

printf("thread level supported: UNRECOGNIZED\n");

exit(-1);

}

for (i=0; i < 3; i++)

{

rc = pthread_create(&thrdid[i],(void*)NULL,(void*)thrdsub,(void*)&thrdrank[i]);

if (rc < 0) { printf("create of thread failed with rc=%d\n",rc); exit(-1); }

}

for (i=0; i < 3; i++) { thread_join(thrdid[i],NULL); }

MPI_Finalize();

exit(0);

}

void *thrdsub(void *arg)

{

int mythrdrank, num_sent;

char s_buff[1024] = "hello", r_buff[1024];

MPI_Status status;

mythrdrank = *((int *)arg);

printf("comm_rank=%d mythrdrank=%d\n",comm_rank,mythrdrank);

if (Level == MPI_THREAD_SINGLE || Level == MPI_THREAD_FUNNELED)

{ if (mythrdrank > 0) pthread_exit(NULL); }

for (num_sent=0; num_sent < num_msgs; num_sent++)

{if (comm_rank == 0)

{ if (Level == MPI_THREAD_SINGLE || Level == MPI_THREAD_FUNNELED)

{ pthread_mutex_lock(&mpi_lock); }

MPI_Send(s_buff,strlen(s_buff)+1,MPI_CHAR,1,mythrdrank,MPI_COMM_WORLD);

r_buff[0] = '\0';

MPI_Recv(r_buff,1024,MPI_CHAR,1,mythrdrank,MPI_COMM_WORLD,&status);

if (strcmp(s_buff,r_buff) != 0)

{printf("comm_rank=%d mythrdrank=%d bad recv\n",comm_rank,mythrdrank);

exit(-1); }

if (Level == MPI_THREAD_SINGLE || Level == MPI_THREAD_FUNNELED)



{



pthread_mutex_unlock(&mpi_lock); }



} else

{ if (Level == MPI_THREAD_SINGLE || Level == MPI_THREAD_FUNNELED)

{ pthread_mutex_lock(&mpi_lock); }

r_buff[0] = '\0';

MPI_Recv(r_buff,1024,MPI_CHAR,0,mythrdrank,MPI_COMM_WORLD,&status);

if (strcmp(s_buff,r_buff) != 0)

{ printf("comm_rank=%d mythrdrank=%d bad recv\n",comm_rank,mythrdrank);

exit(-1); }

MPI_Send(s_buff,strlen(s_buff)+1,MPI_CHAR,0,mythrdrank,MPI_COMM_WORLD);

if (Level == MPI_THREAD_SINGLE || Level == MPI_THREAD_FUNNELED)

{ pthread_mutex_unlock(&mpi_lock); }

}/* printf("sent and recvd\n"); */

}

return(NULL);

}



Ví dụ 2.

Trình chạy trên mạng nhiều máy tính, mỗi máy tính có nhiều thread chạy song song.

Nhiệm vụ chung là tính tích của 2 vector, mỗi máy đảm nhận trách nhiệm nhân trên một

khoảng, và trách nhiệm này được giao cho các thread. Các thread trên cùng một máy sử

dụng công cụ Mutext để tránh hiện tượng race khi cộng dồn kết quả. Đây là kết quả do

từng máy tính tính ra, và chúng được cộng dồn lại với nhau bằng lệnh MPI_Reduce.

#include

#include "mpi.h"

#include

typedef struct

{ double

*a;

double

*b;

double sum;

int veclen;

int numthrds;

} DOTDATA;

#define N_THREADS 8

#define VECLEN 100

DOTDATA dotstr;

pthread_t callThd[N_THREADS];

pthread_mutex_t mutexsum;

void *dotprod(void *arg)

{ int i, start, end, mythrd, len, numthrds, myid;

double mysum, *x, *y;

mythrd = (int)arg;

MPI_Comm_rank (MPI_COMM_WORLD, &myid);

numthrds = dotstr.numthrds;



len = dotstr.veclen;

start = myid*numthrds*len + mythrd*len;

end = start + len;

x = dotstr.a; y = dotstr.b;

/* perform the dot product and assign result to mysum. */

mysum = 0;

for (i=start; i
/* lock & unlock for updating mysum.*/

pthread_mutex_lock (&mutexsum);

printf("Task %d thread %d adding %f to node sum of %f\n", myid, mythrd, mysum,

dotstr.sum);

dotstr.sum += mysum;

pthread_mutex_unlock (&mutexsum);

pthread_exit((void*)0);

}

/* main program creates threads on each node and the main thread does all the MPI calls. */

int main(int argc, char* argv[])

{ int i,len=VECLEN;

int myid, numprocs;

int nump1, numthrds;

double *a, *b;

double nodesum, allsum;

int status;

pthread_attr_t attr;

MPI_Init (&argc, &argv);

MPI_Comm_size (MPI_COMM_WORLD, &numprocs);

MPI_Comm_rank (MPI_COMM_WORLD, &myid);

/* Assign storage and initialize values */

numthrds=N_THREADS;

a = (double*) malloc (numprocs*numthrds*len*sizeof(double));

b = (double*) malloc (numprocs*numthrds*len*sizeof(double));

for (i=0; i
dotstr.veclen = len; dotstr.a = a; dotstr.b = b; dotstr.sum=0;

dotstr.numthrds=N_THREADS;

/*Create thread attribute to specify main thread to join with all the threads created himby. */

pthread_attr_init(&attr );

pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);

pthread_mutex_init (&mutexsum, NULL);

/* Create a mutex */

/* Create threads within this node to perform the dotproduct */

for(i=0;i
pthread_attr_destroy(&attr ); /* Release the thread attribute handle */

/* Wait on the other threads within this node */

for(i=0;i
nodesum = dotstr.sum;

printf("Task %d node sum is %f\n",myid, nodesum);

/* After the dot product, perform a summation of results on each node */



MPI_Reduce (&nodesum, &allsum, 1, MPI_DOUBLE, MPI_SUM, 0, MPI_COMM_WORLD);

if (myid == 0) printf ("Done. MPI with threads version: sum=%f\n", allsum);

MPI_Finalize();

free (a); free (b);

pthread_mutex_destroy(&mutexsum);

exit (0);

}



X.2 MPI & OpenMP.

Để khai thác khả năng của mạng các máy tính, gồm các máy có nhiều vi-xử-lý, chúng ta

có thể sử dụng hỗn hợp phương án lập trình: dùng chỉ thị OpenMP trên từng máy, và

dùng MPI để truyền dữ liệu giữa các máy trong mạng.

Trình ví dụ sau đây làm 2 việc: 1) in ra các số hiệu máy (process), số hiệu thread. 2) Các

tiến trình in ra lời chào được gửi đi từ tiến trình chủ.

// Filename: hello.C

#include

#include

#include

int main(int argc, char* argv[])

{

int nthreads, tid;

int myid, nprocs;

char buf[32];

MPI_Init(&argc, &argv);

// start MPI

MPI_Comm_rank(MPI_COMM_WORLD, &myid);

// get my processor id

MPI_Comm_size(MPI_COMM_WORLD, &nprocs);

// get number of procs

printf("MPI Process number %d of %d is alive\n", myid, nprocs);

#pragma omp parallel private(nthreads, tid)

{

tid = omp_get_thread_num();

// Obtain thread id

if (tid==0) {

// Only master thread does this

nthreads = omp_get_num_threads();

printf("Number of threads %d on process %d\n", nthreads, myid);

}

}

if (myid==0) { strcpy(buf, "an MPI message from process 0"); }

MPI_Bcast(buf,32,MPI_CHARACTER,0,MPI_COMM_WORLD);

if (myid!=0) {printf("Process %d got %s\n", myid, buf); }

MPI_Finalize();

return 0;

}



XI. Phụ lục.

XI.1 Process & Thread trong Microsoft Windows.

Đối với hệ điều hành Microsoft Windows, có thể tạo ra sự đồng bộ giữa các

thread của một process, giữa các thread của những process khác nhau, thậm

chí là các thread của các process chạy trên các máy khác nhau trong cùng

một mạng cục bộ.

Quá trình tạo lập và sử dụng thread theo Microsoft Windows được giới thiệu

sau đây, thông qua việc so sánh74 với các kiến thức kinh điển về thread.

XI.2 Tạo lập thread.

Bảng so sánh các lệnh cần thiết để tạo lập một thread trong hai mơ hình.

Win 32 Microsoft Thread

#include



HANDLE

life;

void Proc( char *MyID )

{...

_endthread();

}

life = (HANDLE) _beginthread(Proc,0,&A);

WaitForSingleObject(life, INFINITE);



Posix Thread

#include

pthread_t tid;

void * Proc ( void *MyID )

{...

return NULL;

}

pthread_create(&tid,NULL,&Proc,&A);

pthread_join(tid, NULL);



Sau đây là ví dụ về tạo lập thread.

Lệnh



_beginthread( ThreadProc, 0, &A );



kích hoạt trình con



void ThreadProc( char *MyID ); thành thread.



Trong trình ví dụ sau, 4 thread được tạo ra và mỗi thread sử dụng lệnh

for (i=0; i<1000000; i++) { sum ++;}



để cộng 1000000 lần số 1 vào ô nhớ “sum”.

Trước khi thốt khỏi trình chúng giảm chỉ số N_Thread và trình main() sẽ

dựa vào điều kiện N_Thread>0 để biết là có còn phải chờ nữa khơng.



74



Do vậy, chúng ta chỉ chú trọng đến các yếu tố giống nhau giữa chúng.



390



#include

#include

#include

int

int









N_Thread;

sum=0;



/* Number of threads started */



void ThreadProc( char *MyID )

{int i;

for (i=0; i<1000000; i++) { sum ++;}

N_Thread --;

_endthread();

}

void main()

{ int A=0, B=1, C=2, D=3;

N_Thread =4;

_beginthread( ThreadProc, 0, &A );

_beginthread( ThreadProc, 0, &B );

_beginthread( ThreadProc, 0, &C );

_beginthread( ThreadProc, 0, &D );



/* Create threads */



do {;} while(N_Thread >0);

printf("%d\n",sum);

}



4 thread chạy song song, hy vọng tổng nhận được sẽ là 4000000. Ấy vậy mà

trên thực tế thì khơng phải lúc nào cũng thu được kết quả như vậy. Chạy

trình 300 lần thì ¼ số trường hợp trình in ra kết quả nhỏ hơn.

Hiện tượng này chúng ta đã biết, đó là hiệu ứng rượt đuổi “race”. Nó xảy ra

là do các thread truy cập quá tự do vào biến “sum” và “N_Thread”. Nhiều

thread cùng “chen nhau” cộng vào một ơ nhớ chung, vì vậy, có thể có thread

khơng thành cơng.

Trình sau đây sử dụng đoạn lệnh assemply để biến việc làm tranh nhau trên

thành tuần tự75.

#include

#include

#include











int

int

int



N_Thread;

sum=0;

mutex = 1;



/* Number of threads started */



75



Do chỉ phải thực hiện có 4 lần trừ, mỗi lần 1, cho nên khả năng xảy ra hiện tượng race với biến

N_Thread là rất ít.



391



Tài liệu bạn tìm kiếm đã sẵn sàng tải về

X. Công nghệ tổ hợp

Tải bản đầy đủ ngay(0 tr)

×