C++ তে কনকারেন্সি (Concurrency) হল একাধিক কাজ বা থ্রেড একসাথে কার্যকরভাবে চলা, যা একটি প্রোগ্রামের কর্মক্ষমতা এবং প্রতিক্রিয়া সময় উন্নত করতে সাহায্য করে। এটি একাধিক থ্রেড বা প্রসেসের মাধ্যমে একাধিক কাজ চালানোর ক্ষমতা প্রদান করে, যার ফলে CPU বা অন্যান্য সিস্টেম রিসোর্সগুলো আরও কার্যকরভাবে ব্যবহার করা যায়।
C++11 থেকে C++ তে কনকারেন্সি সমর্থন শুরু হয়েছে এবং বর্তমানে C++17 ও C++20 তে কনকারেন্সির জন্য অনেক উন্নত ফিচার যোগ করা হয়েছে। এই কনকারেন্সি সাপোর্টের মাধ্যমে C++ প্রোগ্রামাররা মাল্টি-থ্রেডিং এবং প্যারালাল প্রোগ্রামিংয়ের সুবিধা নিতে পারেন।
C++ তে কনকারেন্সি এর মূল উপাদানগুলি
std::threadstd::mutexএবংstd::lock_guardstd::atomicstd::futureএবংstd::asyncstd::condition_variablestd::asyncএবংstd::futurestd::barrier(C++20)
১. std::thread
C++11 এ std::thread ক্লাসটি পরিচিতি পায় যা মাল্টি-থ্রেডিং বাস্তবায়ন করতে ব্যবহৃত হয়। এটি থ্রেড তৈরি এবং পরিচালনা করার জন্য ব্যবহৃত হয়। std::thread ক্লাস ব্যবহার করে একাধিক থ্রেড চালানো যায়।
উদাহরণ (Basic Thread Creation):
#include <iostream>
#include <thread>
// থ্রেড ফাংশন
void print_hello() {
std::cout << "Hello from thread!" << std::endl;
}
int main() {
// থ্রেড তৈরি এবং শুরু করা
std::thread t(print_hello);
// মেইন থ্রেডে কাজ চলাকালীন থ্রেডের কাজ শেষ হওয়ার জন্য অপেক্ষা
t.join(); // join() ফাংশন থ্রেডের কাজ শেষ না হওয়া পর্যন্ত অপেক্ষা করবে
return 0;
}ব্যাখ্যা:
std::threadব্যবহার করে নতুন থ্রেড তৈরি করা হয় যাprint_hello()ফাংশন চালায়।join(): এটি থ্রেডের কাজ সম্পন্ন না হওয়া পর্যন্ত মেইন থ্রেডকে অপেক্ষা করায়।
২. std::mutex এবং std::lock_guard
কনকারেন্সিতে রেস কন্ডিশন (race conditions) থেকে রক্ষা পেতে std::mutex এবং std::lock_guard ব্যবহৃত হয়। যখন একাধিক থ্রেড একসাথে একটি শেয়ার্ড রিসোর্সে অ্যাক্সেস করে, তখন mutex ব্যবহার করে সেই রিসোর্সে একসাথে একাধিক থ্রেডের অ্যাক্সেস আটকানো যায়।
উদাহরণ (Mutex and Lock):
#include <iostream>
#include <thread>
#include <mutex>
std::mutex mtx; // মিউটেক্স অবজেক্ট
void print_numbers(int id) {
std::lock_guard<std::mutex> lock(mtx); // lock_guard ব্যবহার করে মিউটেক্স লক করা
std::cout << "Thread " << id << " is printing numbers." << std::endl;
for (int i = 0; i < 5; i++) {
std::cout << "Thread " << id << ": " << i << std::endl;
}
}
int main() {
std::thread t1(print_numbers, 1);
std::thread t2(print_numbers, 2);
t1.join();
t2.join();
return 0;
}ব্যাখ্যা:
std::mutex mtx;: এটি একটি মিউটেক্স অবজেক্ট যা থ্রেডের মধ্যে রিসোর্স অ্যাক্সেস সিঙ্ক্রোনাইজ করতে ব্যবহৃত হয়।std::lock_guard<std::mutex> lock(mtx);: এটি একটি স্বয়ংক্রিয়ভাবে মিউটেক্স লক করার উপায়, যা রিসোর্সে একাধিক থ্রেডের অ্যাক্সেস নিয়ন্ত্রণ করে।
৩. std::atomic
C++ তে std::atomic ক্লাস ব্যবহৃত হয় এমন ভেরিয়েবলগুলির জন্য যেগুলো একাধিক থ্রেড দ্বারা অ্যাক্সেস এবং পরিবর্তিত হতে পারে। এটি একটি থ্রেড সেফ অপারেশন নিশ্চিত করে যা সাধারণ std::mutex এর মতো সিঙ্ক্রোনাইজেশন মেকানিজমের থেকে দ্রুত।
উদাহরণ (Atomic Operation):
#include <iostream>
#include <thread>
#include <atomic>
std::atomic<int> counter(0);
void increment() {
for (int i = 0; i < 1000; ++i) {
counter++;
}
}
int main() {
std::thread t1(increment);
std::thread t2(increment);
t1.join();
t2.join();
std::cout << "Final counter value: " << counter.load() << std::endl;
return 0;
}ব্যাখ্যা:
std::atomic<int> counter(0);: এটি একটি অ্যাটমিক ভেরিয়েবল যা একাধিক থ্রেডের মাধ্যমে নিরাপদভাবে অ্যাক্সেস করা যায়।counter++: এই অ্যাটমিক অপারেশনটি থ্রেডের মধ্যে নিরাপদভাবে বৃদ্ধি পায়, কারণ এটি লক-মুক্ত।
৪. std::future এবং std::async
C++11 এ std::future এবং std::async ফাংশনগুলি সহায়ক ফিচার যা থ্রেড থেকে ভবিষ্যত মান (future value) উদ্ধার করতে ব্যবহৃত হয়। std::async একটি অ্যাসিঙ্ক্রোনাস কাজ চালায় এবং std::future এটি থেকে রিটার্ন মান পাওয়ার জন্য ব্যবহৃত হয়।
উদাহরণ (Async and Future):
#include <iostream>
#include <thread>
#include <future>
int calculate_square(int x) {
return x * x;
}
int main() {
// std::async ব্যবহার করে ফাংশন অ্যাসিঙ্ক্রোনাসভাবে চালানো
std::future<int> result = std::async(std::launch::async, calculate_square, 5);
// থ্রেডের ফলাফল পাওয়া
std::cout << "Square: " << result.get() << std::endl;
return 0;
}ব্যাখ্যা:
std::async: এটি একটি ফাংশন অ্যাসিঙ্ক্রোনাসভাবে চালানোর জন্য ব্যবহৃত হয়, যার ফলে এটি একটিstd::futureঅবজেক্ট রিটার্ন করে।result.get(): এটিfutureঅবজেক্ট থেকে আসন্ন ফলাফল পেতে ব্যবহৃত হয়।
৫. std::condition_variable
std::condition_variable একটি খুব গুরুত্বপূর্ণ কনসেপ্ট যা থ্রেড সিঙ্ক্রোনাইজেশন ব্যবস্থায় ব্যবহৃত হয়। এটি এক বা একাধিক থ্রেডকে একটি নির্দিষ্ট শর্ত পূর্ণ না হওয়া পর্যন্ত অপেক্ষা করতে দেয় এবং একবার শর্ত পূর্ণ হলে তাদের পুনরায় চালু করে।
উদাহরণ (Condition Variable):
#include <iostream>
#include <thread>
#include <mutex>
#include <condition_variable>
std::mutex mtx;
std::condition_variable cv;
bool ready = false;
void print_id(int id) {
std::unique_lock<std::mutex> lck(mtx);
while (!ready) cv.wait(lck);
std::cout << "Thread " << id << std::endl;
}
void go() {
std::unique_lock<std::mutex> lck(mtx);
ready = true;
cv.notify_all(); // সব থ্রেডকে জানানো যে তারা কাজ শুরু করতে পারে
}
int main() {
std::thread threads[10];
for (int i = 0; i < 10; ++i)
threads[i] = std::thread(print_id, i);
std::cout << "10 threads ready to race...\n";
go();
for (auto& th : threads) th.join();
return 0;
}ব্যাখ্যা:
cv.wait(lck): এটি থ্রেডটিকে একটি নির্দিষ্ট শর্ত (যেমনready) পূর্ণ না হওয়া পর্যন্ত অপেক্ষা করায়।cv.notify_all(): এটি সব থ্রেডকে সতর্ক করে যে তারা তাদের কাজ শুরু করতে পারে।
উপসংহার
C++ তে কনকারেন্সি একটি শক্তিশালী কনসেপ্ট যা মাল্টি-থ্রেডিং এবং প্যারালাল প্রোগ্রামিংয়ের মাধ্যমে প্রোগ্রামকে আরও কার্যকরী এবং দ্রুত করতে সাহায্য করে। std::thread, **`std::
mutex**, **std::atomic**, **std::future**, **std::async**, এবং **std::condition_variable`** এর মতো কনকারেন্সি টুলস সি++ এর মধ্যে কার্যকরী সিঙ্ক্রোনাইজেশন এবং থ্রেড পরিচালনা সহজ করে। C++11 থেকে শুরু করে, C++ প্রোগ্রামিংয়ের কনকারেন্সি ফিচারগুলি অনেক উন্নত হয়েছে এবং বর্তমানে একটি অত্যন্ত কার্যকরী মেকানিজম সরবরাহ করছে।
Read more