
Multithreading Trong C++ Là Gì?
Bạn có biết khi tạo ra các Thread chạy song song, chương trình sẽ có hiệu năng tốt hơn là chỉ luôn chạy một luồng main thread.
Về cơ bản, MultiThread là khả năng của một nền tảng (hệ điều hành, máy ảo vv) hoặc các ứng dụng/chương trình để tạo ra một quá trình bao gồm nhiều Thread được thực thi. Khi tạo ra các Thread chạy song song, chương trình sẽ có hiệu năng tốt hơn là chỉ luôn chạy một luồng main thread.
Chúng ta có thể chia ra làm 2 loại multitasking: Process-based và Thread-based tương ứng: dựa trên tiến trình(process) và dựa trên luồng(thread).
Process Based Multitasking là gì?
- Trong process based multitasking các tiến trình(process) có thể chạy cùng lúc.
- Trong process based multitasking các tiến trình(process) được coi là đơn vị tính nhỏ nhất.
- Process based multitasking tiêu tốn nhiều tài nguyên hơn.
- Process cần phải cấp phát không gian địa chỉ (address space) cho chính nó.
Example: Chúng ta có thể vừa nghe nhạc, vừa lướt web cùng một lúc. Processes trong trường hợp này chính là chương trình nghe nhạc (music player) và trình duyệt web(browser).
Thread Based Multitasking là gì?
- Trong thread based multitasking các thread có thể chạy cùng lúc
- Trong thread based multitasking thì thread được coi là đơn vị tính nhỏ nhất.
- Thread based multitasking tiêu tốn ít tài nguyên hơn so với process based multitasking.
- Các thread chia sẻ không gian địa chỉ (address space) với nhau.
Example: Khi sử dụng trình duyệt web(browser), ta có thể vừa lướt web, vừa download file cùng một thời điểm. Ở đây, ta nhận thấy lướt web là một thread và việc download là một thread khác.
Tạo 1 Thread như thế nào?
Một thread có thể được create bằng nhiều cách khách nhau.
- Sử dụng Function Object
- Sử dụng Function Pointer
- Sử dụng Lambda Function
Đầu tiền, chúng ta include header thread để sử dụng
import<thread>
1. Tạo một thread sử dụng Function Object
Funtion object có thể được sử dụng như một param trong thread object. Để sử dụng, chúng ta cần có 1 class trong class đó và orverload operrator(). Function được overload sẽ chưa code để thực thi khi thread được tạo.
Define class cho function object
class functioObject_class {
// Overload () operator
void operator()(params)
{
// code to be executed
}
};
Bây giờ, chúng ta có thể tạo một thread sử dụng function object
std::thread thread_object(functioObject_class (), params)
Mình sẽ giải thích thêm về cách mà thread object được define. Tham số đầu tiền của thread object được truyền vào chính là một constructor của function object, tham số thứ 2 là tham số của chính function object được truyền vào.
2. Tạo một thread sử dụng Function Pointer
Một function pointer được define theo cách sau.
void funct_pointer(params)
//code to be executed
}
//tao một thread với function pointer
std::thread thread_obj(funct_pointer, params);
Lưu ý rằng các argument được truyền vào chính là param của function và được truyền vào sau function name trong thread_obj.
3. Tạo một thread sử dụng Lamba Expression
Ngoài Function Object và Function Pointer, lambda cũng có thể được dùng như một param truyền vào trong thread object. Đoạn code sau sẽ minh họa các dùng lambda
// Define a lambda expression
auto f = [](params) {
// code for execution
};
// tạo một thread object với lambda
std::thread thread_object(f, params);
Ở ví dụ trên, chúng ta đã define một biểu thức lambda f, truyền vào thread object như một argument và params của f là argument thứ hai.
Code ví dụ cụ thể sử dụng function pointer.
#include <iostream>
#include <thread>
using namespace std;
int main()
{
auto f = [](int n) {
for (int i = 0; i < n; i++)
cout << "Thread 3 :: callable => lambda expression\n";
};
thread lambda_thread(f, 2);
}
Chạy thử đoạn code trên, ngay lập tức chúng ta gặp phải 1 runtime error.
Tại sao vậy nhỉ? Mọi thứ nhìn rất đúng rồi mà? Tại sao lại lỗi được? Thực ra câu trả lời ở đây rất đơn giản, nếu để ý một chút chúng ta sẽ tìm ra nguyên nhân khá dễ dàng.
Main thread đã tạo ra một thread mới là th3. Bản chất các thread là chạy song song, độc lập với nhau nên Main thread này sẽ không đợi chờ gì lambda_thread cả. Nếu may mắn, lambda_thread kết thúc trước khi Main thread tự hủy, code sẽ cho ra output bình thường, tuy nhiên trong trường hợp ngược lại (rất dễ xảy ra), khi Main thread kết thúc, lambda_thread vẫn chạy sẽ đễn lỗi như trên. Tất cả các thread phải kết thúc trước khi Main thread kết thúc. Nếu không, code sẽ bị lỗi khi runtime.
4. Join Thread
Cách khắc phục vấn đề trên cũng vô cùng đơn giản. Suy nghĩ một theo logic thông thường, nếu thread chưa kịp kết thúc thì ta phải làm cho main thread chờ cho thread kia kết thúc mới được hủy, như vậy là không lỗi được nữa phải không? Để chờ một thread kết thúc, C++ đã cung cấp cho chúng ta function std::thread::join(). Funtion này có nhiệm vụ làm cho main thread chờ cho đến khi thread sử dụng nó kết thúc. Với đoạn code trên, đơn giản ta chỉ cần sử dụng join() cho lambda_thread.
#include <iostream>
#include <thread>
using namespace std;
int main()
{
auto f = [](int n) {
for (int i = 0; i < n; i++)
cout << "Thread 3 :: callable => lambda expression\n";
};
thread lambda_thread(f, 2);
lambda_thread.join();
}
output:
Dưới đây là ví dụ hoàn chỉnh cho việc sử dụng các thread:
#include <iostream>
#include <thread>
using namespace std;
void foo(int Z)
{
for (int i = 0; i < Z; i++) {
cout << "Thread using function"
" pointer as callable: " << i << endl;
}
}
class thread_obj {
public:
void operator()(int x)
{
for (int i = 0; i < x; i++)
cout << "Thread using function"
" object as callable: " << i << endl;
}
};
int main()
{
cout << "Threads 1 and 2 and 3 "
"operating independently" << endl;
// thread sử dụng function pointer
thread th1(foo, 3);
// thread sử dụng function object
thread th2(thread_obj(), 3);
// Define a Lambda Expression
auto f = [](int x) {
for (int i = 0; i < x; i++)
cout << "Thread using lambda"
" expression as callable: " << i << endl;
};
// thread sử dụng lamda expression
thread th3(f, 3);
// chờ th1 kết thúc
th1.join();
// chờ th2 kết thúc
th2.join();
// chờ th3 kết thúc
th3.join();
return 0;
}
output:
Tạm kết
Như vậy, bài viết đã hướng dẫn các bạn cách sử dụng thread trong C++. Trong thời gian tới, mình sẽ tiếp tục giới thiệu tới các bạn các bài viết hướng dẫn sử dụng thread trong Java hoặc trong một ứng dụng Android.
Post Comment