Giới thiệu OpenMP trong C++

Bài viết này nhằm mục đích giới thiệu một cách cơ bản nhất về OpenMP, một bộ thư viện mở rộng C/C++/Fortran nhằm cho phép thực hiện song song vào source code hiện tại mà không cần phải viết lại nó.

Tầm quan trọng của đa luồng

Khi mà tốc độ của CPU không còn có thể cải thiện thêm nhiều thì hệ thống multicore bắt đầu trở lên phổ biến hơn. Do đó, các lập trình viên cũng cần nắm bắt về parallel programming nhiều hơn, đưa ứng dụng thực hiện nhiều công việc hơn cùng lúc.

Các trình biên dịch hỗ trợ OpenMP

  • GCC: Sử dụng -fopenmp
  • Clang++: Sử dụng -fopenmp
  • Solaris Studio: Sử dụng -xopenmp
  • Intel C Compiler: Sử dụng -openmp
  • Microsoft Visual C++: Sử dụng /openmp

OpenMP trong C++

OpenMP bao gồm một tập các chỉ dẫn biên dịch #pragma nhằm chỉ dẫn cho chương trình hoạt động. Các pragmađược thiết kế nhằm mục đích nếu các trình biên dịch không hỗ trợ thì chương trình vẫn có thể hoạt động bình thường, nhưng sẽ không có bất kỳ tác vụ song song nào được thực hiện như khi sử dụng OpenMP

Dưới đây là một ví dụ đơn giản về OpenMP nhằm tăng tốc độ thực hiện vòng lặp for

Ví dụ sử dụng nhiều thread thực hiện vòng lặp for

Ví dụ sử dụng một thread thực hiện vòng lặp for

Ví dụ khởi tạo bảng bằng thực hiện song song (sử dụng nhiều thread trên thiết bị khác)

Từ OpenMP 4.0 hỗ trợ việc offloading code trên các thiết bị khác, như GPU.

Ví dụ tính toán hệ số Mandelbrot trên host computer

Trong các ví dụ trên, khi remove #pragma, kết quả tính toán của chương trình vẫn đúng như kỳ vọng.

Chỉ khi trình biên dịch được biên dịch với #pragma, nó trở thành một chương trình chạy song song. Nó có thể thực hiện tính toán N giá trị đồng thời với N là số thread thực hiện.

Cú pháp

Tất cả các chỉ dẫn OpenMP trong C/C++ đều được dùng thông qua #pragma omp theo sau là các thông số và kết thúc bằng một ký hiệu xuống dòng. #pragma chỉ được áp dụng vào đoạn chương trình ngay sau nó, ngoại trừ lệnh barrier và flush

Chỉ dẫn parrallel

Chỉ dẫn parrallel bắt đầu một đoạn code thực hiện song song. Nó tạo ra một team bao gồm N threads (N được chỉ định tại thời điểm chạy chương trình, thông thường bằng số nhân CPU, nhưng có thể bị ảnh hưởng bởi một số lý do khác), các lệnh xử lý tiếp theo ngay sau #pragma hoặc block tiêp theo (trong giới hạn {}) sẽ được thực hiện song song. Sau đoạn xử lý này, các thread sẽ được join lại về một

Đoạn code này sẽ tạo ra một nhóm threads, mỗi thread thực hiện cùng một đoạn code in ra màn hình dòng chữ “Hello”, số lần in ra màn hình bằng số thread dược tạo ra. Ví dụ hệ thóng dual-core sẽ in ra màn hình 2 lần “Hello”. Chú ý rằng, nó có thể in ra màn hình đoạn chữ kiểu “HeHlellolo”, tùy thuộc vào hệ thống bởi vì việc in ra màn hình được thực hiện song song. Sau dấu “}”, các threads sẽ được join lại thành một như khi chạy một chương trình thông thường.

GCC thực hiện đoạn chương trình này bằng cách tạo ra một hàm ảo và đưa các đoạn code tương ứng vào hàm đó, do đó các biến được định nghĩa trong block trở thành biến cục bộ của hàm.

Có thể sử dụng điều kiện cho việc sử lý song song như sau

Nếu parallelism_enabled được đặt giá trị bằng 0 thì số thread được tạo ra cho việc xử lý vòng lặp for là 1.

Chỉ dẫn lặp for

Chỉ dẫn for sẽ chia vòng lặp for mà mỗi thread trong nhóm thread hiện tại thực hiện một phần của vòng lặp

Vòng lặp này sẽ in ra màn hình từ 0..9. Tuy nhiên nó có thể in ra không theo tứ tự, ví dụ

Vòng lặp này có thể hình dung bằng đoạn code tương ứng như sau:

Chú ý rằng #pragma omp for chia các phần của vòng lặp cho các thread khác nhau trong team. Mỗi team là một nhóm các thread thực hiện chương trình. Khi chương trình bắt đầu, team bao gồm duy nhất một thành viên là thread chính đang chạy chương trình.

Để tạo ra một team mới, cần chỉ định rõ từ khóa parrallel

Cám ơn các bạn đã đọc bài viết này, hy vọng nó sẽ giúp ích cho các bạn!

Giới thiệu OpenMP trong C++
5 (100%) 10 votes

Nhận xét