البرمجة غير المتزامنة في C++: دليل شامل
تتطلب التطبيقات الحديثة أداءً عاليًا واستجابة سريعة. تتيح البرمجة غير المتزامنة في C++ تنفيذ العمليات الطويلة (الإدخال/الإخراج، طلبات الشبكة، الحسابات المعقدة) دون حظر الخيط الرئيسي. في هذا الدليل، سنشرح الآليات الرئيسية في C++ للعمل غير المتزامن: من std::thread و std::async الكلاسيكية إلى coroutines الحديثة في C++20. ستتعلم كيفية كتابة كود غير متزامن فعال وآمن.
1. الأساسيات: std::thread و std::async
لنبدأ بالأدوات الأساسية. يقوم std::thread بإنشاء خيط تنفيذ جديد، لكنه يتطلب إدارة يدوية ومزامنة. الخيار الأكثر ملاءمة هو std::async، الذي يشغل دالة بشكل غير متزامن ويعيد std::future للحصول على النتيجة.
#include <iostream>#include <future>#include <chrono>
int long_running_task(int input) { std::this_thread::sleep_for(std::chrono::seconds(2)); return input * 10;}
int main() { std::cout << "نقوم بتشغيل مهمة غير متزامنة..."; std::future<int> result = std::async(std::launch::async, long_running_task, 5); // نقوم بشيء مفيد أثناء تنفيذ المهمة std::cout << "الخيط الرئيسي يواصل العمل..."; // الحصول على النتيجة (يتم الحظر إذا لم تكتمل المهمة بعد) int value = result.get(); std::cout << "النتيجة: " << value << std::endl; return 0;}النقاط الرئيسية:
- std::launch::async — يضمن التشغيل في خيط منفصل.
- std::launch::deferred — يؤجل التنفيذ حتى استدعاء
get(). - طريقة
get()تحظر الخيط حتى الحصول على النتيجة.
2. العمل المتقدم: std::promise و std::future
عند الحاجة لنقل نتيجة من خيط إلى آخر، استخدم الزوج std::promise و std::future. يقوم promise بتعيين القيمة، بينما يستلمها future. هذا مفيد بشكل خاص في تجميع الخيوط أو سلاسل المهام.
#include <iostream>#include <future>#include <thread>
void worker(std::promise<int> prom) { try { int result = 42; // حسابات معقدة prom.set_value(result); } catch (...) { prom.set_exception(std::current_exception()); }}
int main() { std::promise<int> prom; std::future<int> fut = prom.get_future(); std::thread t(worker, std::move(prom)); // الحصول على النتيجة int value = fut.get(); std::cout << "تم استلام القيمة: " << value << std::endl; t.join(); return 0;}الميزات الهامة:
- لا يمكن نسخ
promise، بل نقله فقط. - يتم نقل الاستثناءات عبر
set_exception. - يمكن استخدام
futureمرة واحدة فقط (استلام لمرة واحدة).
3. Coroutines في C++20: النهج الحديث
تعتبر coroutines أداة قوية تمت إضافتها في C++20. تسمح بإيقاف واستئناف تنفيذ الدالة دون حظر الخيط. هذا مثالي لعمليات الإدخال/الإخراج غير المتزامنة والمولدات.
#include <iostream>#include <coroutine>#include <future>
struct SimpleTask { struct promise_type { SimpleTask get_return_object() { return {}; } std::suspend_never initial_suspend() { return {}; } std::suspend_never final_suspend() noexcept { return {}; } void return_void() {} void unhandled_exception() { std::exit(1); } };};
SimpleTask async_operation() { std::cout << "بداية coroutine";