مقدمة في البرمجة غير المتزامنة في C++
\n\nفي عالم تطوير البرمجيات الحديث، يلعب أداء التطبيقات واستجابتها دورًا رئيسيًا. تتيح البرمجة غير المتزامنة في C++ الاستخدام الفعال لموارد النظام من خلال تنفيذ مهام متعددة في وقت واحد دون حظر الخيط الرئيسي. هذا مهم بشكل خاص عند العمل مع طلبات الشبكة، وعمليات الإدخال/الإخراج، والحسابات الطويلة.
\n\nعلى عكس النهج المتزامن التقليدي، حيث يتم تنفيذ كل عملية بشكل تسلسلي، يمكن للكود غير المتزامن تشغيل المهام في الخلفية والحصول على النتائج فور جاهزيتها. في هذا الدليل، سنستعرض الأدوات الرئيسية للبرمجة غير المتزامنة في C++، بدءًا من المفاهيم البسيطة وصولاً إلى الإمكانيات الحديثة لمعيار C++20.
\n\nأساسيات عدم التزامن: std::async و std::future
\n\nأبسط طريقة لبدء العمل مع البرمجة غير المتزامنة في C++ هي استخدام std::async. هذه الدالة تبدأ مهمة بشكل غير متزامن وتعيد كائن std::future الذي يحتوي على نتيجة التنفيذ.
مثال أساسي مع std::async
\n\n#include <iostream>\n#include <future>\n#include <chrono>\n\nint عملية_طويلة() {\n std::this_thread::sleep_for(std::chrono::seconds(2));\n return 42;\n}\n\nint main() {\n std::cout << "نبدأ المهمة غير المتزامنة..." << std::endl;\n \n // بدء مهمة غير متزامنة\n std::future<int> نتيجة = std::async(std::launch::async, عملية_طويلة);\n \n std::cout << "الخيط الرئيسي يواصل العمل..." << std::endl;\n \n // الحصول على النتيجة (يحظر الخيط حتى الجاهزية)\n int قيمة = نتيجة.get();\n std::cout << "النتيجة: " << قيمة << std::endl;\n \n return 0;\n}\n\nسياسة التشغيل std::launch::async تضمن تنفيذ الدالة في خيط منفصل. البديل هو std::launch::deferred، الذي يؤجل التنفيذ حتى لحظة استدعاء get().
العمل مع مهام متعددة
\n\nالبرمجة غير المتزامنة فعالة بشكل خاص عند التنفيذ المتوازي لعدة مهام مستقلة:
\n\n#include <iostream>\n#include <future>\n#include <vector>\n\nint احسب_المربع(int x) {\n return x * x;\n}\n\nint main() {\n std::vector<std::future<int>> مهام;\n \n // بدء عدة مهام غير متزامنة\n for (int i = 1; i <= 5; ++i) {\n مهام.push_back(std::async(std::launch::async, احسب_المربع, i));\n }\n \n // جمع النتائج\n for (auto& مهمة : مهام) {\n std::cout << "النتيجة: " << مهمة.get() << std::endl;\n }\n \n return 0;\n}\n\nأدوات متقدمة: std::promise و std::packaged_task
\n\nللتحكم الأكثر مرونة في العمليات غير المتزامنة في C++، تم توفير std::promise و std::packaged_task. تسمح هذه الأدوات بنقل القيم بين الخيوط وتغليف الكائنات القابلة للاستدعاء.
استخدام std::promise
\n\nstd::promise يسمح بتعيين قيمة سيتم الحصول عليها لاحقًا عبر كائن std::future المقابل:
#include <iostream>\n#include <future>\n#include <thread>\n\nvoid خيط_منتج(std::promise<std::string> وعد) {\n try {\n std::string بيانات = "بيانات مهمة من الخيط";\n // تعيين القيمة\n وعد.set_value(بيانات);\n } catch(...) {\n // معالجة الاستثناءات\n وعد.set_exception(std::current_exception());\n }\n}\n\nint main() {\n std::promise<std::string> وعد;\n std::future<std::string> مستقبل = وعد.get_future();\n \n std::thread خيط(خ