Trong mô hình lập trình MPI, việc tính toán bao gồm một hoặc nhiều tiến trình truyền thông với nhau bằng cách goi thư viện hàm để gửi và nhận thông điệp từ những tiến trình khác. Trong hầu hết các thể hiện MPI, một tập hợp cố định các tiến trình được tạo ra khi khởi tạo chương trình, và một tiến trình được tạo bởi một bộ xử lý.
Hai phương thức chính cần thiết cho mô hình lập trình truyền thông điệp dạng này là:
• Phương thức tạo các tiến trình riêng biệt để thực thi trên các máy tính khác nhau.
• Phương thức gửi và nhận thông điệp.
Việc tạo lập tiến trình
Phiên bản 1 của MPI chỉ hỗ trợ việc tạo lập tiến trình tĩnh. Tức là, tất cả các tiến trình được xác định trước khi thực hiện và bắt đầu cùng với nhau. Phiên bản 2 của MPI đã hỗ trợ việc tạo lập tiến trình động nhưng nó thường không được sử dụng vì tổng phí của việc tạo lập tiến trình động.
Trong mô hình lập trình MPI thường sử dụng mô hình tính toán SPMD. Trong hệ thống thường có một tiến trình chủ (master) điều khiển các tiến trình khác được gọi là tiến trình tớ (slave)
Các tiến trình được đánh số từ0đến (p−1)dùng để định danh các tiến trình, các số này gọi là hạng của tiến trình, plà số tiến trình được sử dụng.
Số lượng các hàm trong MPI rất nhiều, tuy nhiên chúng ta có thể xây dựng chương trình dựa trên các hàm cơ bản sau:
Các hàm quản lý môi trường
• Hàm khởi tạo MPI
int MPI_Init(Int∗ argc, char∗ argv)
Ý nghĩa: hàm này dùng để khởi tạo môi trường truyền thông điệp MPI. Nó phải được gọi trước bất cứ hàm MPI nào. Tham số của nó là con trỏ trỏ tới các tham số của hàmmain( ).
• Hàm kết thúc MPI
int MPI_Finalize(void)
Ý nghĩa: đây là hàm đóng môi trường MPI. Sau lời gọi hàm này không còn lời gọi hàm MPI nào có hiệu lực.
Các hàm truyền thông điệp điểm-điểm
• Hàm gửi thông điệp
int MPI_Send(void∗buf, int count, MPI_Datatype datatype, int dest, int tag, MPI_Comm comm)
Trong đó,
– buf: địa chỉ bắt đầu của bộ đệm gửi
– count: số các thành phần trong bộ đệm
– datatype: kiểu dữ liệu của mỗi thành phần trong bộ đệm
– dest: hạng của tiến trình nhận
– tag: nhãn của thông điệp được gửi
– comm: bộ truyền thông điệp, đó là tập hợp của các tiến trình mà các tiến trình có thể gửi và nhận thông điệp.
Ý nghĩa: hàm này dùng để gửi thông điệp có nhãn làtagvà chứa dữ liệu ở bộ đệmbuf với số lượngcountphần tử kiểudatatypetới tiến trình có số hiệudest.
Một thông điệp được gửi tới một tiến trình cụ thể và được đánh dấu bởi một nhãn (giá trị là số nguyên) do người sử dụng xác định. Các nhãn được dùng để phân biệt những kiểu thông điệp khác nhau mà một tiến trình gửi (hoặc nhận). Nhãn thông điệp có thể dùng MPI_ANY_TAG khi thông điệp được gửi (hoặc nhận) có thể ở bất kỳ định dạng nào. Tương tự, ta có thể dùng MPI_ANY_SOURCE để nhận thông điệp từ bất kỳ tiến trình nào.
• Hàm nhận thông điệp
int MPI_Recv(void∗buf, int count, MPI_Datatype datatype, int source, int tag, MPI_Status status)
Ý nghĩa: hàm này dùng để nhận thông điệp từ tiến trình có số hiệusourcevới nhãn làtag dữ liệu và lưu vào bộ đệmbuf với số phần tử làcountcó kiểu dữ liệudatatypevà trả lại thông tin về dữ liệu thật sự nhận được trong biến trạng thái status.
status là kiểu dữ liệu có cấu trúc, chứa ít nhất 3 thành phần là số hiệu tiến trình gửi (source), nhãn (tag) và mã lỗi. Nhãn thông báo nhận được là status.MPI_TAG và hạng của tiến trình gửi là status.MPI_SOURCE. Khi số lượng phần tử nhận được có thể nhỏ hơncount, hàm sau đây có chức năng trả lại số lượng các phần tử nhận đượcMPI_Get_count(&status, datatype, &nelements).
Các hàm truyền thông tập thể
• Hàm quảng bá thông điệp (loan tin)
Hình 1.12:Hàm giao tiếp tập thể của MPI
int root, MPI_Comm comm)
Trong đó, các tham số buf, count, datatype, commtương tự như trong hàm MPI_Send. Tham biếnrootchính là hạng của tiến trình tiến hành loan tin. Ý nghĩa: hàm này dùng để gửi một nội dungbuf từ tiến trình có hạngroottới tất cả các tiến trình trong bộ truyền thông.
• Hàm tổng hợp dữ liệu
int MPI_Gather(void∗sendbuf, int sendcount, MPI_Datatype sendtype, void ∗recvbuf, int recvcount, MPI_Datatype recvtype, int root, MPI_comm comm)
Ý nghĩa: tiến trình có số hiệuroot thu thập dữ liệu trong bộ đệmsendbuf từ tất cả các tiến trình trong bộ truyền thông và lưu vào trong bộ đệm recvbuf theo thứ tự hạng của các tiến trình.
• Hàm phân phối dữ liệu
sendtype, void∗recvbuf, int recvcount, MPI_Datatype recvtype, MPI_comm comm)
Ý nghĩa: tiến trình có số hiệurootphân phối dữ liệu từsendbuf tới tất cả các tiến trình trong bộ truyền thông theo thứ tự hạng của tiến trình.
• Hàm tổng hợp toàn bộ dữ liệu
MPI_allGather(void∗sendbuf, int sendcount, MPI_Datatype sendtype, void∗recvbuf, int recvcount, MPI_Datatype recvtype, MPI_comm comm)
Ý nghĩa: các tiến trình thu thập dữ liệu trong bộ đệm sendbuf từ tất cả các tiến trình trong bộ truyền thông và lưu vào trong bộ đệmrecvbuf theo thứ tự hạng của tiến trình.
Các hàm quản lý nhóm
• Hàm lấy hạng của tiến trình
int MPI_Comm_rank(MPI_Comm comm, int ∗rank) Ý nghĩa: hàm này trả lại giá trị hạng của tiến trình trong bộ truyền thông đang gọi hàm.
• Hàm lấy số tiến trình
int MPI_Comm_size(MPI_Comm com, int ∗size)
Ý nghĩa: hàm này trả lại giá trị là số lượng các tiến trình trong bộ truyền thôngcom.
Ví dụ về một chương trình MPI đơn giản
Viết chương trình in ra tên máy và chỉ số rank của process MPI đang thực thi tên máy.
#include<stdio.h>
#include<mpi.h>
int main(int argc, char∗ argv[]) {
int length;
char name[BUFSIZ]; MPI_Init(&argc,&argv);
MPI_Get_processor_name(name,&length); printf("%s Hello world\n", name);
MPI_Finalize(); }
Chương 2
Kĩ thuật phân hoạch, chia để trị và một số ứng dụng
Phân hoạch(partitioning) và chia để trị(divide-and-conquer) là hai kỹ thuật cơ bản để xây dựng một chương trình song song. Hai kĩ thuật này có liên quan tới nhau. Trong kĩ thuật phân hoạch, bài toán được chia thành các phần riêng lẻ và mỗi phần được tính toán riêng. Kĩ thuật chia để trị thường áp dụng kĩ thuật phân hoạch trong phép đệ quy để chia liên tục bài toán thành các phần nhỏ hơn trước khi giải quyết các phần nhỏ hơn và hợp các kết quả lại.