<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Modern C++ on kenji.blog</title><link>http://kenji.blog/ar/tags/modern-c++/</link><description>Recent content in Modern C++ on kenji.blog</description><generator>Hugo -- gohugo.io</generator><language>ar</language><copyright>kenjinote</copyright><lastBuildDate>Sat, 12 Sep 2026 08:00:00 +0900</lastBuildDate><atom:link href="http://kenji.blog/ar/tags/modern-c++/index.xml" rel="self" type="application/rss+xml"/><item><title>مقدمة في البرمجة متعددة الخيوط والمعالجة غير المتزامنة في C++ (std::async)</title><link>http://kenji.blog/ar/p/cpp-multithreading-and-async-guide/</link><pubDate>Sat, 12 Sep 2026 08:00:00 +0900</pubDate><guid>http://kenji.blog/ar/p/cpp-multithreading-and-async-guide/</guid><description>&lt;img src="http://kenji.blog/p/cpp-multithreading-and-async-guide/img/eyecatch.jpg" alt="Featured image of post مقدمة في البرمجة متعددة الخيوط والمعالجة غير المتزامنة في C++ (std::async)" />&lt;p>في تطوير البرمجيات الحديثة، تعتبر البرمجة متعددة الخيوط (multithreading) ضرورية لتحقيق أقصى استفادة من أداء وحدات المعالجة المركزية متعددة النواة (multi-core CPUs). منذ الإصدار C++11، قدمت C++ واجهات برمجة التطبيقات (APIs) للبرمجة متعددة الخيوط والمعالجة غير المتزامنة (&lt;code>&amp;lt;thread&amp;gt;&lt;/code>, &lt;code>&amp;lt;mutex&amp;gt;&lt;/code>, &lt;code>&amp;lt;condition_variable&amp;gt;&lt;/code>, &lt;code>&amp;lt;future&amp;gt;&lt;/code>) كمكتبة قياسية، مما يتيح لك تنفيذ معالجة متزامنة آمنة ومحمولة دون كتابة تعليمات برمجية تعتمد على المنصة (مثل خيوط POSIX أو واجهة برمجة تطبيقات Windows). علاوة على ذلك، مع كل ترقية للإصدار مثل C++14 و C++17 و C++20، تمت إضافة ميزات أكثر أمانًا وتقدمًا مثل &lt;code>std::scoped_lock&lt;/code> و &lt;code>std::jthread&lt;/code>.&lt;/p>
&lt;p>في هذا المقال، سنشرح بشكل شامل أساسيات البرمجة متعددة الخيوط في C++، وآليات المزامنة لمنع تعارض البيانات، بالإضافة إلى المفاهيم الحديثة للمعالجة غير المتزامنة (&lt;code>std::async&lt;/code>) ومجمعات الخيوط (thread pools) مع أمثلة برمجية مفصلة.&lt;/p>
&lt;hr>
&lt;h2 id="1-أساسيات-المعالجة-المتزامنة-وقانون-أمدال-amdahls-law">1. أساسيات المعالجة المتزامنة وقانون أمدال (Amdahl&amp;rsquo;s Law)
&lt;/h2>&lt;p>الهدف الرئيسي من استخدام خيوط المعالجة المتعددة هو &amp;ldquo;تحسين الأداء&amp;rdquo;، ولكن لا يمكن موازاة (توازي) البرنامج بأكمله. وهنا تكمن أهمية &lt;strong>قانون أمدال (Amdahl&amp;rsquo;s Law)&lt;/strong>.&lt;/p>
&lt;p>قانون أمدال هو نموذج يتنبأ بمدى تحسن أداء النظام ككل عند موازاة وتسريع جزء من البرنامج.&lt;/p>
$$ S(N) = \frac{1}{(1 - P) + \frac{P}{N}} $$
&lt;ul>
&lt;li>$S(N)$ : الحد الأقصى النظري لنسبة زيادة السرعة&lt;/li>
&lt;li>$P$ : نسبة الجزء القابل للموازاة من البرنامج بأكمله (0 ≤ $P$ ≤ 1)&lt;/li>
&lt;li>$N$ : عدد المعالجات (الخيوط)&lt;/li>
&lt;/ul>
&lt;p>الحقيقة المهمة التي توضحها هذه الصيغة هي: &amp;ldquo;بغض النظر عن مدى زيادة عدد المعالجات $N$، فإن الجزء التسلسلي $(1 - P)$ الذي لا يمكن موازاته سيصبح عنق الزجاجة (bottleneck)، وهناك حد أقصى لزيادة السرعة&amp;rdquo;. على سبيل المثال، حتى إذا كان $90\%$ من البرنامج قابلاً للموازاة ($P = 0.9$)، طالما أن الـ $10\%$ المتبقية هي معالجة تسلسلية، فحتى مع استخدام عدد لا نهائي من المعالجات، فإن السرعة ستزداد بحد أقصى $10$ مرات فقط ($S(\infty) = 1 / 0.1$).&lt;/p>
&lt;p>لذلك، عند القيام بالبرمجة متعددة الخيوط في C++، لا يقتصر الأمر على مجرد زيادة عدد الخيوط، بل يتطلب الأمر &lt;strong>تصميماً يقلل من أجزاء المعالجة التسلسلية (مثل تعارض الأقفال أو العبء الإضافي للمزامنة) قدر الإمكان&lt;/strong>.&lt;/p>
&lt;hr>
&lt;h2 id="2-أساسيات-الخيوط-stdthread-و-stdjthread-c20">2. أساسيات الخيوط: &lt;code>std::thread&lt;/code> و &lt;code>std::jthread&lt;/code> (C++20)
&lt;/h2>&lt;h3 id="خيط-stdthread-التقليدي-c11">خيط &lt;code>std::thread&lt;/code> التقليدي (C++11)
&lt;/h3>&lt;p>تم تقديم &lt;code>std::thread&lt;/code> في C++11، وهو الفئة الأساسية لتنفيذ الدوال وتعبيرات لامدا (lambda expressions) في خيط جديد.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;span class="lnt">16
&lt;/span>&lt;span class="lnt">17
&lt;/span>&lt;span class="lnt">18
&lt;/span>&lt;span class="lnt">19
&lt;/span>&lt;span class="lnt">20
&lt;/span>&lt;span class="lnt">21
&lt;/span>&lt;span class="lnt">22
&lt;/span>&lt;span class="lnt">23
&lt;/span>&lt;span class="lnt">24
&lt;/span>&lt;span class="lnt">25
&lt;/span>&lt;span class="lnt">26
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-cpp" data-lang="cpp">&lt;span class="line">&lt;span class="cl">&lt;span class="cp">#include&lt;/span> &lt;span class="cpf">&amp;lt;iostream&amp;gt;&lt;/span>&lt;span class="cp">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp">#include&lt;/span> &lt;span class="cpf">&amp;lt;thread&amp;gt;&lt;/span>&lt;span class="cp">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp">&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kt">void&lt;/span> &lt;span class="nf">workerFunction&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="kt">int&lt;/span> &lt;span class="n">id&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">cout&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="s">&amp;#34;Worker &amp;#34;&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="n">id&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="s">&amp;#34; is running on thread &amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">this_thread&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">get_id&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">endl&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kt">int&lt;/span> &lt;span class="nf">main&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">cout&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="s">&amp;#34;Main thread id: &amp;#34;&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">this_thread&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">get_id&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">endl&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// إنشاء الخيط وبدء تنفيذه
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="kr">thread&lt;/span> &lt;span class="n">t1&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">workerFunction&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// إنشاء خيط باستخدام تعبير لامدا
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="kr">thread&lt;/span> &lt;span class="n">t2&lt;/span>&lt;span class="p">([](&lt;/span>&lt;span class="kt">int&lt;/span> &lt;span class="n">id&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">cout&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="s">&amp;#34;Lambda Worker &amp;#34;&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="n">id&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="s">&amp;#34; is running.&amp;#34;&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">endl&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">},&lt;/span> &lt;span class="mi">2&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// انتظار انتهاء الخيط (join)
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="n">t1&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">join&lt;/span>&lt;span class="p">();&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">t2&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">join&lt;/span>&lt;span class="p">();&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">cout&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="s">&amp;#34;All threads completed.&amp;#34;&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">endl&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>النقطة المهمة التي يجب الانتباه إليها في &lt;code>std::thread&lt;/code> هي أنه &lt;strong>يجب دائماً استدعاء &lt;code>join()&lt;/code> أو &lt;code>detach()&lt;/code> قبل تدمير الكائن&lt;/strong>. إذا تم استدعاء المُدمّر (destructor) الخاص بـ &lt;code>std::thread&lt;/code> دون استدعاء أي منهما، فسيتم استدعاء &lt;code>std::terminate()&lt;/code>، مما يؤدي إلى انهيار البرنامج. لضمان الأمان ضد الاستثناءات (exception safety)، كان من الضروري كتابة فئة غلاف مخصصة باستخدام نمط RAII.&lt;/p>
&lt;h3 id="خيط-stdjthread-الحديث-c20">خيط &lt;code>std::jthread&lt;/code> الحديث (C++20)
&lt;/h3>&lt;p>في C++20، تم تقديم &lt;code>std::jthread&lt;/code> (خيط الانضمام - joining thread) لحل هذه العيوب. يستدعي &lt;code>std::jthread&lt;/code> الدالة &lt;code>join()&lt;/code> تلقائياً في المُدمّر الخاص به، مما يسمح بالانتظار الآمن لإنهاء الخيط حتى عند حدوث استثناء. كما أنه مزود بميزة للإلغاء التعاوني للخيوط عبر &lt;code>std::stop_token&lt;/code>.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;span class="lnt">16
&lt;/span>&lt;span class="lnt">17
&lt;/span>&lt;span class="lnt">18
&lt;/span>&lt;span class="lnt">19
&lt;/span>&lt;span class="lnt">20
&lt;/span>&lt;span class="lnt">21
&lt;/span>&lt;span class="lnt">22
&lt;/span>&lt;span class="lnt">23
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-cpp" data-lang="cpp">&lt;span class="line">&lt;span class="cl">&lt;span class="cp">#include&lt;/span> &lt;span class="cpf">&amp;lt;iostream&amp;gt;&lt;/span>&lt;span class="cp">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp">#include&lt;/span> &lt;span class="cpf">&amp;lt;thread&amp;gt;&lt;/span>&lt;span class="cp">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp">#include&lt;/span> &lt;span class="cpf">&amp;lt;chrono&amp;gt;&lt;/span>&lt;span class="cp">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp">&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kt">int&lt;/span> &lt;span class="nf">main&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// C++20: std::jthread
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="c1">// يمكن اكتشاف طلب الإلغاء عن طريق استقبال std::stop_token كمعامل أول
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">jthread&lt;/span> &lt;span class="n">jt&lt;/span>&lt;span class="p">([](&lt;/span>&lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">stop_token&lt;/span> &lt;span class="n">stoken&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">while&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="o">!&lt;/span>&lt;span class="n">stoken&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">stop_requested&lt;/span>&lt;span class="p">())&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">cout&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="s">&amp;#34;Working...&amp;#34;&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">endl&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">this_thread&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">sleep_for&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">chrono&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">milliseconds&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">500&lt;/span>&lt;span class="p">));&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">cout&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="s">&amp;#34;Stop requested. Exiting thread.&amp;#34;&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">endl&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">});&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">this_thread&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">sleep_for&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">chrono&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">seconds&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">2&lt;/span>&lt;span class="p">));&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// طلب الإلغاء صراحةً
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="n">jt&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">request_stop&lt;/span>&lt;span class="p">();&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// لا حاجة لاستدعاء join() يدوياً، حيث يتم الانضمام تلقائياً في مُدمّر jthread
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="k">return&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;hr>
&lt;h2 id="3-تجنب-تعارض-البيانات-والمزامنة-كائنات-الاستبعاد-المتبادل-mutex-والأقفال-locks">3. تجنب تعارض البيانات والمزامنة: كائنات الاستبعاد المتبادل (Mutex) والأقفال (Locks)
&lt;/h2>&lt;p>عندما تصل عدة خيوط إلى نفس منطقة الذاكرة (مثل متغير) في نفس الوقت ويقوم أحدها على الأقل بالكتابة، يحدث &lt;strong>تعارض البيانات (Data Race)&lt;/strong>. في معيار C++، يؤدي تعارض البيانات إلى سلوك غير محدد (Undefined Behavior). لمنع حدوث ذلك، من الضروري استخدام التحكم في الاستبعاد المتبادل باستخدام &lt;code>std::mutex&lt;/code>.&lt;/p>
&lt;h3 id="stdmutex-و-stdlock_guard">&lt;code>std::mutex&lt;/code> و &lt;code>std::lock_guard&lt;/code>
&lt;/h3>&lt;p>لا يُنصح باستدعاء &lt;code>std::mutex::lock()&lt;/code> و &lt;code>unlock()&lt;/code> الخام يدوياً، لوجود خطر ألا يتم استدعاء &lt;code>unlock()&lt;/code> عند حدوث استثناء، مما يؤدي إلى حالة الجمود (Deadlock). في C++، نستخدم &lt;code>std::lock_guard&lt;/code> (في C++11) أو &lt;code>std::scoped_lock&lt;/code> (في C++17) التي تستخدم نمط RAII.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;span class="lnt">16
&lt;/span>&lt;span class="lnt">17
&lt;/span>&lt;span class="lnt">18
&lt;/span>&lt;span class="lnt">19
&lt;/span>&lt;span class="lnt">20
&lt;/span>&lt;span class="lnt">21
&lt;/span>&lt;span class="lnt">22
&lt;/span>&lt;span class="lnt">23
&lt;/span>&lt;span class="lnt">24
&lt;/span>&lt;span class="lnt">25
&lt;/span>&lt;span class="lnt">26
&lt;/span>&lt;span class="lnt">27
&lt;/span>&lt;span class="lnt">28
&lt;/span>&lt;span class="lnt">29
&lt;/span>&lt;span class="lnt">30
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-cpp" data-lang="cpp">&lt;span class="line">&lt;span class="cl">&lt;span class="cp">#include&lt;/span> &lt;span class="cpf">&amp;lt;iostream&amp;gt;&lt;/span>&lt;span class="cp">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp">#include&lt;/span> &lt;span class="cpf">&amp;lt;vector&amp;gt;&lt;/span>&lt;span class="cp">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp">#include&lt;/span> &lt;span class="cpf">&amp;lt;thread&amp;gt;&lt;/span>&lt;span class="cp">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp">#include&lt;/span> &lt;span class="cpf">&amp;lt;mutex&amp;gt;&lt;/span>&lt;span class="cp">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp">&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">mutex&lt;/span> &lt;span class="n">g_mutex&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kt">int&lt;/span> &lt;span class="n">g_counter&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kt">void&lt;/span> &lt;span class="nf">incrementCounter&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="kt">int&lt;/span> &lt;span class="n">iterations&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">for&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="kt">int&lt;/span> &lt;span class="n">i&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">;&lt;/span> &lt;span class="n">i&lt;/span> &lt;span class="o">&amp;lt;&lt;/span> &lt;span class="n">iterations&lt;/span>&lt;span class="p">;&lt;/span> &lt;span class="o">++&lt;/span>&lt;span class="n">i&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// يتم فك القفل (unlock) تلقائياً عند الخروج من النطاق (scope)
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">lock_guard&lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">mutex&lt;/span>&lt;span class="o">&amp;gt;&lt;/span> &lt;span class="n">lock&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">g_mutex&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">++&lt;/span>&lt;span class="n">g_counter&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kt">int&lt;/span> &lt;span class="nf">main&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">vector&lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="kr">thread&lt;/span>&lt;span class="o">&amp;gt;&lt;/span> &lt;span class="n">threads&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">for&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="kt">int&lt;/span> &lt;span class="n">i&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">;&lt;/span> &lt;span class="n">i&lt;/span> &lt;span class="o">&amp;lt;&lt;/span> &lt;span class="mi">10&lt;/span>&lt;span class="p">;&lt;/span> &lt;span class="o">++&lt;/span>&lt;span class="n">i&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">threads&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">emplace_back&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">incrementCounter&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">10000&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">for&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="k">auto&lt;/span>&lt;span class="o">&amp;amp;&lt;/span> &lt;span class="nl">t&lt;/span> &lt;span class="p">:&lt;/span> &lt;span class="n">threads&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">t&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">join&lt;/span>&lt;span class="p">();&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">cout&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="s">&amp;#34;Final counter value: &amp;#34;&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="n">g_counter&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">endl&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// ستكون النتيجة كما هو متوقع 100000
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="k">return&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h3 id="stdunique_lock">&lt;code>std::unique_lock&lt;/code>
&lt;/h3>&lt;p>يُعد &lt;code>std::lock_guard&lt;/code> قفلاً بسيطاً يعتمد على النطاق، ولكن إذا كنت بحاجة إلى تحكم أكثر مرونة (مثل القفل المؤجل، القفل المقيد بوقت، أو فك القفل في المنتصف)، فيجب استخدام &lt;code>std::unique_lock&lt;/code>. في القسم التالي الذي يشرح &lt;code>std::condition_variable&lt;/code>، يُعد استخدام &lt;code>std::unique_lock&lt;/code> إلزامياً.&lt;/p>
&lt;hr>
&lt;h2 id="4-التواصل-بين-الخيوط-stdcondition_variable">4. التواصل بين الخيوط: &lt;code>std::condition_variable&lt;/code>
&lt;/h2>&lt;p>لتنفيذ &amp;ldquo;نمط المنتج والمستهلك (Producer-Consumer Pattern)&amp;quot;، حيث ينتظر خيط معين حتى يتم استيفاء شرط ما، ويقوم خيط آخر بإرسال إشعار عندما يتحقق هذا الشرط، يتم استخدام &lt;code>std::condition_variable&lt;/code>.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;span class="lnt">16
&lt;/span>&lt;span class="lnt">17
&lt;/span>&lt;span class="lnt">18
&lt;/span>&lt;span class="lnt">19
&lt;/span>&lt;span class="lnt">20
&lt;/span>&lt;span class="lnt">21
&lt;/span>&lt;span class="lnt">22
&lt;/span>&lt;span class="lnt">23
&lt;/span>&lt;span class="lnt">24
&lt;/span>&lt;span class="lnt">25
&lt;/span>&lt;span class="lnt">26
&lt;/span>&lt;span class="lnt">27
&lt;/span>&lt;span class="lnt">28
&lt;/span>&lt;span class="lnt">29
&lt;/span>&lt;span class="lnt">30
&lt;/span>&lt;span class="lnt">31
&lt;/span>&lt;span class="lnt">32
&lt;/span>&lt;span class="lnt">33
&lt;/span>&lt;span class="lnt">34
&lt;/span>&lt;span class="lnt">35
&lt;/span>&lt;span class="lnt">36
&lt;/span>&lt;span class="lnt">37
&lt;/span>&lt;span class="lnt">38
&lt;/span>&lt;span class="lnt">39
&lt;/span>&lt;span class="lnt">40
&lt;/span>&lt;span class="lnt">41
&lt;/span>&lt;span class="lnt">42
&lt;/span>&lt;span class="lnt">43
&lt;/span>&lt;span class="lnt">44
&lt;/span>&lt;span class="lnt">45
&lt;/span>&lt;span class="lnt">46
&lt;/span>&lt;span class="lnt">47
&lt;/span>&lt;span class="lnt">48
&lt;/span>&lt;span class="lnt">49
&lt;/span>&lt;span class="lnt">50
&lt;/span>&lt;span class="lnt">51
&lt;/span>&lt;span class="lnt">52
&lt;/span>&lt;span class="lnt">53
&lt;/span>&lt;span class="lnt">54
&lt;/span>&lt;span class="lnt">55
&lt;/span>&lt;span class="lnt">56
&lt;/span>&lt;span class="lnt">57
&lt;/span>&lt;span class="lnt">58
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-cpp" data-lang="cpp">&lt;span class="line">&lt;span class="cl">&lt;span class="cp">#include&lt;/span> &lt;span class="cpf">&amp;lt;iostream&amp;gt;&lt;/span>&lt;span class="cp">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp">#include&lt;/span> &lt;span class="cpf">&amp;lt;thread&amp;gt;&lt;/span>&lt;span class="cp">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp">#include&lt;/span> &lt;span class="cpf">&amp;lt;mutex&amp;gt;&lt;/span>&lt;span class="cp">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp">#include&lt;/span> &lt;span class="cpf">&amp;lt;condition_variable&amp;gt;&lt;/span>&lt;span class="cp">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp">#include&lt;/span> &lt;span class="cpf">&amp;lt;queue&amp;gt;&lt;/span>&lt;span class="cp">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp">&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">mutex&lt;/span> &lt;span class="n">g_mtx&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">condition_variable&lt;/span> &lt;span class="n">g_cv&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">queue&lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="kt">int&lt;/span>&lt;span class="o">&amp;gt;&lt;/span> &lt;span class="n">g_dataQueue&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kt">bool&lt;/span> &lt;span class="n">g_isFinished&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nb">false&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kt">void&lt;/span> &lt;span class="nf">producer&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">for&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="kt">int&lt;/span> &lt;span class="n">i&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">;&lt;/span> &lt;span class="n">i&lt;/span> &lt;span class="o">&amp;lt;=&lt;/span> &lt;span class="mi">5&lt;/span>&lt;span class="p">;&lt;/span> &lt;span class="o">++&lt;/span>&lt;span class="n">i&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">this_thread&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">sleep_for&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">chrono&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">milliseconds&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">200&lt;/span>&lt;span class="p">));&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">lock_guard&lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">mutex&lt;/span>&lt;span class="o">&amp;gt;&lt;/span> &lt;span class="n">lock&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">g_mtx&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">g_dataQueue&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">push&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">i&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">cout&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="s">&amp;#34;Produced: &amp;#34;&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="n">i&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">endl&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">g_cv&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">notify_one&lt;/span>&lt;span class="p">();&lt;/span> &lt;span class="c1">// إشعار المستهلك
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">lock_guard&lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">mutex&lt;/span>&lt;span class="o">&amp;gt;&lt;/span> &lt;span class="n">lock&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">g_mtx&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">g_isFinished&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nb">true&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">g_cv&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">notify_one&lt;/span>&lt;span class="p">();&lt;/span> &lt;span class="c1">// إشعار بالانتهاء
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kt">void&lt;/span> &lt;span class="nf">consumer&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">while&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="nb">true&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">unique_lock&lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">mutex&lt;/span>&lt;span class="o">&amp;gt;&lt;/span> &lt;span class="n">lock&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">g_mtx&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// الانتظار حتى يتحقق الشرط (قائمة الانتظار ليست فارغة، أو تم تعيين علامة الانتهاء)
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="c1">// تحديد الشرط بتعبير لامدا لمنع الاستيقاظ الزائف (Spurious Wakeup)
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="n">g_cv&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">wait&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">lock&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="p">[]{&lt;/span> &lt;span class="k">return&lt;/span> &lt;span class="o">!&lt;/span>&lt;span class="n">g_dataQueue&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">empty&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="o">||&lt;/span> &lt;span class="n">g_isFinished&lt;/span>&lt;span class="p">;&lt;/span> &lt;span class="p">});&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">while&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="o">!&lt;/span>&lt;span class="n">g_dataQueue&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">empty&lt;/span>&lt;span class="p">())&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kt">int&lt;/span> &lt;span class="n">val&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">g_dataQueue&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">front&lt;/span>&lt;span class="p">();&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">g_dataQueue&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">pop&lt;/span>&lt;span class="p">();&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// فك القفل وإجراء العمليات الثقيلة (في هذه الحالة، الطباعة فقط)
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="n">lock&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">unlock&lt;/span>&lt;span class="p">();&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">cout&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="s">&amp;#34;Consumed: &amp;#34;&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="n">val&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">endl&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">lock&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">lock&lt;/span>&lt;span class="p">();&lt;/span> &lt;span class="c1">// الحصول على القفل مرة أخرى
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">g_isFinished&lt;/span> &lt;span class="o">&amp;amp;&amp;amp;&lt;/span> &lt;span class="n">g_dataQueue&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">empty&lt;/span>&lt;span class="p">())&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">break&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kt">int&lt;/span> &lt;span class="nf">main&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="kr">thread&lt;/span> &lt;span class="n">t1&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">producer&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="kr">thread&lt;/span> &lt;span class="n">t2&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">consumer&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">t1&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">join&lt;/span>&lt;span class="p">();&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">t2&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">join&lt;/span>&lt;span class="p">();&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>في هذا المثال، تضع دالة &lt;code>std::condition_variable::wait&lt;/code> الخيط في حالة سكون (sleep) حتى يتحقق الشرط، مما يمنع الاستهلاك المهدر لموارد وحدة المعالجة المركزية (حلقات الانتظار النشطة - busy waiting).&lt;/p>
&lt;hr>
&lt;h2 id="5-المعالجة-غير-المتزامنة-عالية-التجريد-stdfuture-stdpromise-stdasync">5. المعالجة غير المتزامنة عالية التجريد: &lt;code>std::future&lt;/code>, &lt;code>std::promise&lt;/code>, &lt;code>std::async&lt;/code>
&lt;/h2>&lt;p>على الرغم من أن &lt;code>std::thread&lt;/code> و &lt;code>std::mutex&lt;/code> اللتين ذكرناهما حتى الآن قويتان، إلا أنهما تجلبان آليات الخيوط منخفضة المستوى لنظام التشغيل مباشرة إلى C++، مما يجعل التعليمات البرمجية معقدة عند التعامل مع الحصول على النتائج أو تمرير الاستثناءات. إذا كنت ترغب في إجراء معالجة متزامنة تُرجع قيمة، أو معالجة غير متزامنة ذات مستوى أعلى، فاستخدم ميزات الترويسة &lt;code>&amp;lt;future&amp;gt;&lt;/code>.&lt;/p>
&lt;h3 id="stdpromise-و-stdfuture">&lt;code>std::promise&lt;/code> و &lt;code>std::future&lt;/code>
&lt;/h3>&lt;p>يمثل &lt;code>std::promise&lt;/code> الجانب الذي &amp;ldquo;يحدد&amp;rdquo; النتيجة، بينما يمثل &lt;code>std::future&lt;/code> الجانب الذي &amp;ldquo;يستقبل&amp;rdquo; النتيجة. تعمل هذه العناصر كقناة آمنة لتمرير النتائج والاستثناءات بين الخيوط.&lt;/p>
&lt;h3 id="المعالجة-المتزامنة-المستندة-إلى-المهام-باستخدام-stdasync">المعالجة المتزامنة المستندة إلى المهام باستخدام &lt;code>std::async&lt;/code>
&lt;/h3>&lt;p>الطريقة الأكثر موصى بها لتنفيذ المهام غير المتزامنة في C++ هي استخدام &lt;code>std::async&lt;/code>. يقوم &lt;code>std::async&lt;/code> بتنفيذ مهمة بشكل غير متزامن ويرجع &lt;code>std::future&lt;/code> للحصول على نتيجتها.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;span class="lnt">16
&lt;/span>&lt;span class="lnt">17
&lt;/span>&lt;span class="lnt">18
&lt;/span>&lt;span class="lnt">19
&lt;/span>&lt;span class="lnt">20
&lt;/span>&lt;span class="lnt">21
&lt;/span>&lt;span class="lnt">22
&lt;/span>&lt;span class="lnt">23
&lt;/span>&lt;span class="lnt">24
&lt;/span>&lt;span class="lnt">25
&lt;/span>&lt;span class="lnt">26
&lt;/span>&lt;span class="lnt">27
&lt;/span>&lt;span class="lnt">28
&lt;/span>&lt;span class="lnt">29
&lt;/span>&lt;span class="lnt">30
&lt;/span>&lt;span class="lnt">31
&lt;/span>&lt;span class="lnt">32
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-cpp" data-lang="cpp">&lt;span class="line">&lt;span class="cl">&lt;span class="cp">#include&lt;/span> &lt;span class="cpf">&amp;lt;iostream&amp;gt;&lt;/span>&lt;span class="cp">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp">#include&lt;/span> &lt;span class="cpf">&amp;lt;future&amp;gt;&lt;/span>&lt;span class="cp">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp">#include&lt;/span> &lt;span class="cpf">&amp;lt;chrono&amp;gt;&lt;/span>&lt;span class="cp">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp">&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kt">int&lt;/span> &lt;span class="nf">complexCalculation&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="kt">int&lt;/span> &lt;span class="n">x&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">cout&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="s">&amp;#34;Calculation started on thread: &amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">this_thread&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">get_id&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">endl&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">this_thread&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">sleep_for&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">chrono&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">seconds&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">2&lt;/span>&lt;span class="p">));&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">x&lt;/span> &lt;span class="o">&amp;lt;&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">throw&lt;/span> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">invalid_argument&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;x must be positive&amp;#34;&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">x&lt;/span> &lt;span class="o">*&lt;/span> &lt;span class="mi">42&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kt">int&lt;/span> &lt;span class="nf">main&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">cout&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="s">&amp;#34;Main thread id: &amp;#34;&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">this_thread&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">get_id&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">endl&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// التنفيذ في خيط منفصل قسراً بتحديد std::launch::async
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">future&lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="kt">int&lt;/span>&lt;span class="o">&amp;gt;&lt;/span> &lt;span class="n">resultFuture&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">async&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">launch&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">async&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">complexCalculation&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">10&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">cout&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="s">&amp;#34;Main thread is doing other work...&amp;#34;&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">endl&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">try&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// عند استدعاء get()، يتم حظر الخيط الحالي والانتظار حتى انتهاء الحساب
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="kt">int&lt;/span> &lt;span class="n">result&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">resultFuture&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">get&lt;/span>&lt;span class="p">();&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">cout&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="s">&amp;#34;Result: &amp;#34;&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="n">result&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">endl&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span> &lt;span class="k">catch&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="k">const&lt;/span> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">exception&lt;/span>&lt;span class="o">&amp;amp;&lt;/span> &lt;span class="n">e&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">cerr&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="s">&amp;#34;Exception caught: &amp;#34;&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="n">e&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">what&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">endl&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>يوضح مخطط التسلسل (Sequence Diagram) التالي سلوك &lt;code>std::async&lt;/code>.&lt;/p>
&lt;div class="mermaid">sequenceDiagram
participant Main as "الخيط الرئيسي"
participant Async as "عامل std::async"
Main->>Async: "std::async(std::launch::async, ...)"
activate Async
Note over Main: "القيام بعمل آخر..."
Main->>Async: "future.get() (يحظر حتى يجهز)"
Note right of Async: "حسابات..."
Async-->>Main: "إرجاع النتيجة أو إلقاء استثناء"
deactivate Async&lt;/div>
&lt;p>يوجد نوعان من سياسات الإطلاق (Launch Policy) التي يمكن تمريرها كمعامل أول في &lt;code>std::async&lt;/code>:&lt;/p>
&lt;ul>
&lt;li>&lt;code>std::launch::async&lt;/code>: يقوم دائمًا بإنشاء خيط جديد (أو تخصيص واحد من مجمع الخيوط) والتنفيذ بشكل غير متزامن.&lt;/li>
&lt;li>&lt;code>std::launch::deferred&lt;/code>: التقييم المؤجل (Lazy evaluation). يتم التنفيذ بشكل متزامن في نفس الخيط المستدعي فقط عندما يتم استدعاء &lt;code>future.get()&lt;/code> أو &lt;code>future.wait()&lt;/code>.&lt;/li>
&lt;/ul>
&lt;p>في حالة الافتراضي (بدون تحديد سياسة)، يعتمد الأمر على التطبيق (Implementation-defined)، وسيتم اختيار أحدهما بناءً على ظروف حمل النظام. إذا كنت ترغب بالتأكيد في التنفيذ غير المتزامن، فيجب الإشارة صراحة إلى &lt;code>std::launch::async&lt;/code>.&lt;/p>
&lt;hr>
&lt;h2 id="6-مفهوم-مجمع-الخيوط-thread-pool">6. مفهوم مجمع الخيوط (Thread Pool)
&lt;/h2>&lt;p>إذا قمت باستدعاء &lt;code>std::async&lt;/code> في كل مرة، أو بإنشاء وتدمير &lt;code>std::thread&lt;/code> داخل حلقة (loop) بشكل متكرر، فإن العبء الإضافي (overhead) الناتج عن تبديل السياق (context switch) للخيوط وتأمين موارد نظام التشغيل يصبح كبيراً ولا يمكن تجاهله. وخاصة عند معالجة عدد كبير من المهام الصغيرة (Fine-grained tasks)، يصبح استخدام مجمع الخيوط (Thread Pool) ضرورياً.&lt;/p>
&lt;p>مجمع الخيوط هو بنية حيث يتم إنشاء عدد معين من خيوط العمال (Worker threads) مسبقاً عند بدء تشغيل التطبيق، ويتم تجميع المهام في قائمة انتظار (Queue)، ومن ثم تتم معالجة المهام بالتسلسل بواسطة خيوط العمال المتاحة (الفارغة).&lt;/p>
&lt;div class="mermaid">graph TD
Client["العميل / الخيط الرئيسي"] -->|Push Task| Queue["قائمة انتظار المهام"]
Queue -->|Pop Task| W1["خيط العامل 1"]
Queue -->|Pop Task| W2["خيط العامل 2"]
Queue -->|Pop Task| W3["خيط العامل N"]
W1 --> Exec["التنفيذ وإرجاع Future"]
W2 --> Exec
W3 --> Exec&lt;/div>
&lt;p>لا تحتوي المكتبة القياسية لـ C++ (حتى إصدار C++23) على فئة مجمع خيوط قياسية، ولكن من الممكن تنفيذ مجمع خيوط فعال في عشرات الأسطر من خلال دمج &lt;code>std::thread&lt;/code>, &lt;code>std::mutex&lt;/code>, &lt;code>std::condition_variable&lt;/code>, &lt;code>std::function&lt;/code>, و &lt;code>std::packaged_task&lt;/code>. في العمليات الفعلية، من الشائع أيضاً استخدام عمليات الإدخال/الإخراج غير المتزامنة من &lt;code>Boost.Asio&lt;/code> أو مكتبات الجهات الخارجية.&lt;/p>
&lt;hr>
&lt;h2 id="7-اعتبارات-الأداء-وقابلية-التوسع-scalability">7. اعتبارات الأداء وقابلية التوسع (Scalability)
&lt;/h2>&lt;p>لتحقيق أفضل أداء في البرمجة متعددة الخيوط، يجب الانتباه ليس فقط إلى موازاة التعليمات البرمجية، ولكن أيضاً إلى بنية الأجهزة (hardware architecture).&lt;/p>
&lt;ul>
&lt;li>&lt;strong>المشاركة الزائفة (False Sharing):&lt;/strong>
على الرغم من أن خيوط متعددة قد تقوم بتحديث متغيرات منفصلة، إلا أنه إذا تم وضع هذه المتغيرات في نفس خط ذاكرة التخزين المؤقت (Cache Line) لوحدة المعالجة المركزية (عادة 64 بايت)، ستحدث مزامنة غير ضرورية للذاكرة للحفاظ على اتساق ذاكرة التخزين المؤقت (Cache Coherency)، مما يؤدي إلى انخفاض الأداء بشكل كبير. لمنع حدوث ذلك، من الضروري استخدام محدد &lt;code>alignas&lt;/code> لمحاذاة المتغيرات على حدود خط التخزين المؤقت.&lt;/li>
&lt;li>&lt;strong>البرمجة الخالية من الأقفال (Lock-Free) و &lt;code>std::atomic&lt;/code>:&lt;/strong>
لتجنب العبء الإضافي المرتبط بقفل/فك قفل كائنات الاستبعاد المتبادل، يُنظر في استخدام العمليات الذرية غير القابلة للتجزئة باستخدام &lt;code>&amp;lt;atomic&amp;gt;&lt;/code> (مثل Compare-And-Swap) أو تقديم هياكل بيانات خالية من الأقفال. ومع ذلك، يتطلب هذا فهماً صحيحاً لترتيب الذاكرة (&lt;code>std::memory_order&lt;/code>) وتكون صعوبة التنفيذ عالية جداً، لذلك لا يتم إدخالها عادةً إلا بعد قياس دقيق للأداء وعندما يُحكم بأنها ضرورية.&lt;/li>
&lt;/ul>
&lt;hr>
&lt;h2 id="8-الخلاصة">8. الخلاصة
&lt;/h2>&lt;p>لقد شرحنا البرمجة متعددة الخيوط والمعالجة غير المتزامنة في C++، من الأساسيات إلى أحدث ميزات C++20. النقاط المهمة هي كالتالي:&lt;/p>
&lt;ol>
&lt;li>&lt;strong>استخدم &lt;code>std::async&lt;/code> كأساس:&lt;/strong> بالنسبة للمهام غير المتزامنة لمرة واحدة أو المعالجة المتزامنة التي تُرجع نتيجة، استخدم &lt;code>std::async&lt;/code> و &lt;code>std::future&lt;/code> لأنهما أكثر أمانًا من إدارة الخيوط يدويًا.&lt;/li>
&lt;li>&lt;strong>استخدم &lt;code>std::jthread&lt;/code> لإدارة الخيوط:&lt;/strong> بالنسبة للخيوط التي تعمل في الخلفية لفترة طويلة، استخدم &lt;code>std::jthread&lt;/code> من C++20 لضمان عملية إنهاء آمنة.&lt;/li>
&lt;li>&lt;strong>استفد من RAII للمزامنة:&lt;/strong> يجب دائماً إجراء قفل كائنات الاستبعاد المتبادل (Mutex) لمنع تعارض البيانات من خلال &lt;code>std::lock_guard&lt;/code> أو &lt;code>std::unique_lock&lt;/code>.&lt;/li>
&lt;li>&lt;strong>كن واعياً بالعبء الإضافي (Overhead):&lt;/strong> تجنب الإنشاء المفرط للخيوط، وقم بتقديم بنية مجمع الخيوط عند الضرورة.&lt;/li>
&lt;/ol>
&lt;p>أخطاء المعالجة المتزامنة (حالة الجمود وتعرض البيانات) منخفضة التكرار وتصنف ضمن أكثر أنواع الأخطاء صعوبة في التصحيح (Debugging). كن دائماً على دراية بأمان الخيوط (Thread Safety)، واختر الأدوات المناسبة من المكتبة القياسية، لتحقيق تطوير نظام قوي وسريع باستخدام C++ الحديثة.&lt;/p></description></item><item><title>استراتيجيات استخدام المؤشرات الذكية (std::unique_ptr / shared_ptr) لمنع تسرب الذاكرة</title><link>http://kenji.blog/ar/p/cpp-smart-pointers-guide-unique-shared-ptr/</link><pubDate>Sat, 12 Sep 2026 07:00:00 +0900</pubDate><guid>http://kenji.blog/ar/p/cpp-smart-pointers-guide-unique-shared-ptr/</guid><description>&lt;img src="http://kenji.blog/p/cpp-smart-pointers-guide-unique-shared-ptr/img/eyecatch.jpg" alt="Featured image of post استراتيجيات استخدام المؤشرات الذكية (std::unique_ptr / shared_ptr) لمنع تسرب الذاكرة" />&lt;p>لطالما كانت إدارة الذاكرة في لغة C++ إحدى أكبر التحديات التي تواجه المطورين لسنوات طويلة. كان أسلوب إدارة الذاكرة التقليدي الذي يعتمد على الاستخدام اليدوي لـ &lt;code>new&lt;/code> و &lt;code>delete&lt;/code> بيئة خصبة لأخطاء برمجية خطيرة مثل تسرب الذاكرة (Memory Leaks)، والمؤشرات المعلقة (Dangling Pointers)، والتحرير المزدوج للذاكرة (Double Free). ولكن مع ظهور C++ الحديثة (Modern C++) بدءاً من معيار C++11، تغير الوضع بشكل جذري. ويكمن جوهر هذا التغيير في &amp;ldquo;المؤشرات الذكية&amp;rdquo; (Smart Pointers).&lt;/p>
&lt;p>في هذا المقال، سنشرح بتفصيل شديد آليات عمل &lt;code>std::unique_ptr&lt;/code> و &lt;code>std::shared_ptr&lt;/code> و &lt;code>std::weak_ptr&lt;/code>، والتي تُعد أدوات قوية للقضاء على تسرب الذاكرة وتحقيق إدارة آمنة وفعالة للموارد. سنتناول استراتيجيات الاستخدام المتقدمة، مع التطرق إلى التطبيق الداخلي (مثل كتلة التحكم والعمليات الذرية)، وتأثيرها على الأداء، والصياغة الرياضية لعد المراجع (Reference Counting).&lt;/p>
&lt;h2 id="1-مقدمة-العصر-المظلم-لإدارة-الذاكرة-في-c-وفجر-modern-c">1. مقدمة: العصر المظلم لإدارة الذاكرة في C++ وفجر Modern C++
&lt;/h2>&lt;p>في تطوير C++ قديماً، كان المطور مسؤولاً بشكل مباشر عن تحرير الذاكرة المخصصة على الكومة (Heap).&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;span class="lnt">4
&lt;/span>&lt;span class="lnt">5
&lt;/span>&lt;span class="lnt">6
&lt;/span>&lt;span class="lnt">7
&lt;/span>&lt;span class="lnt">8
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-cpp" data-lang="cpp">&lt;span class="line">&lt;span class="cl">&lt;span class="kt">void&lt;/span> &lt;span class="nf">legacy_function&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kt">int&lt;/span>&lt;span class="o">*&lt;/span> &lt;span class="n">ptr&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="k">new&lt;/span> &lt;span class="kt">int&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">10&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// ... بعض العمليات ...
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">some_condition&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span>&lt;span class="p">;&lt;/span> &lt;span class="c1">// حدوث تسرب للذاكرة! لم يتم استدعاء delete
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">delete&lt;/span> &lt;span class="n">ptr&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>في كود مثل الموضح أعلاه، عند حدوث استثناء (Exception) أو الإرجاع المبكر (Early Return)، يتم تخطي استدعاء &lt;code>delete&lt;/code> مما يؤدي إلى تسرب الذاكرة. ولمنع ذلك، ظهر نموذج &amp;ldquo;RAII&amp;rdquo; (Resource Acquisition Is Initialization). RAII هو أسلوب يربط بين حجز الموارد وتهيئة الكائن (في دالة البناء)، وتحرير الموارد وتدمير الكائن (في دالة الهدم). المؤشرات الذكية هي فئات في المكتبة القياسية تُطبق نمط RAII هذا على إدارة الذاكرة.&lt;/p>
&lt;h2 id="2-stdunique_ptr-ملكية-حصرية-بدون-تكلفة-إضافية-zero-overhead">2. &lt;code>std::unique_ptr&lt;/code>: ملكية حصرية بدون تكلفة إضافية (Zero-Overhead)
&lt;/h2>&lt;p>&lt;code>std::unique_ptr&lt;/code> هو مؤشر ذكي يمتلك &amp;ldquo;ملكية حصرية&amp;rdquo; (Exclusive Ownership) للكائن المخصص ديناميكيًا. يمكن لمؤشر &lt;code>unique_ptr&lt;/code> واحد فقط أن يمتلك مورداً معيناً في أي وقت.&lt;/p>
&lt;h3 id="21-مبدأ-التكلفة-الصفرية-zero-overhead-principle">2.1 مبدأ التكلفة الصفرية (Zero-Overhead Principle)
&lt;/h3>&lt;p>الميزة الأكبر لـ &lt;code>std::unique_ptr&lt;/code> هي أداؤه. في حالته الافتراضية وبدون وجود حاذف مخصص (Custom Deleter)، يكون حجم &lt;code>std::unique_ptr&lt;/code> مطابقاً تماماً لحجم المؤشر الخام (Raw Pointer). فهو لا يحتوي على أي متغيرات أعضاء غير ضرورية، ولا يستخدم دوال افتراضية (Virtual Functions). بفضل تحسينات المترجم (Compiler Optimization)، يتم تحويل الوصول عبر &lt;code>std::unique_ptr&lt;/code> إلى كود تجميع (Assembly) مكافئ تماماً لاستخدام المؤشر الخام.&lt;/p>
&lt;h3 id="22-نقل-الملكية-و-stdmove">2.2 نقل الملكية و &lt;code>std::move&lt;/code>
&lt;/h3>&lt;p>نظرًا لامتلاكه ملكية حصرية، لا يمكن نسخ &lt;code>std::unique_ptr&lt;/code> (تم حذف دالة البناء بالنسخ ومعامل التعيين بالنسخ باستخدام &lt;code>delete&lt;/code>). لنقل الملكية إلى &lt;code>unique_ptr&lt;/code> آخر، نستخدم &lt;code>std::move&lt;/code> للاستفادة من دلالات النقل (Move Semantics).&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;span class="lnt">16
&lt;/span>&lt;span class="lnt">17
&lt;/span>&lt;span class="lnt">18
&lt;/span>&lt;span class="lnt">19
&lt;/span>&lt;span class="lnt">20
&lt;/span>&lt;span class="lnt">21
&lt;/span>&lt;span class="lnt">22
&lt;/span>&lt;span class="lnt">23
&lt;/span>&lt;span class="lnt">24
&lt;/span>&lt;span class="lnt">25
&lt;/span>&lt;span class="lnt">26
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-cpp" data-lang="cpp">&lt;span class="line">&lt;span class="cl">&lt;span class="cp">#include&lt;/span> &lt;span class="cpf">&amp;lt;iostream&amp;gt;&lt;/span>&lt;span class="cp">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp">#include&lt;/span> &lt;span class="cpf">&amp;lt;memory&amp;gt;&lt;/span>&lt;span class="cp">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp">&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">class&lt;/span> &lt;span class="nc">Resource&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">public&lt;/span>&lt;span class="o">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">Resource&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="p">{&lt;/span> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">cout&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="s">&amp;#34;Resource acquired&lt;/span>&lt;span class="se">\n&lt;/span>&lt;span class="s">&amp;#34;&lt;/span>&lt;span class="p">;&lt;/span> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">~&lt;/span>&lt;span class="n">Resource&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="p">{&lt;/span> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">cout&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="s">&amp;#34;Resource destroyed&lt;/span>&lt;span class="se">\n&lt;/span>&lt;span class="s">&amp;#34;&lt;/span>&lt;span class="p">;&lt;/span> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kt">void&lt;/span> &lt;span class="nf">do_something&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="p">{&lt;/span> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">cout&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="s">&amp;#34;Doing something&lt;/span>&lt;span class="se">\n&lt;/span>&lt;span class="s">&amp;#34;&lt;/span>&lt;span class="p">;&lt;/span> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">};&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kt">void&lt;/span> &lt;span class="nf">process_resource&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">unique_ptr&lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="n">Resource&lt;/span>&lt;span class="o">&amp;gt;&lt;/span> &lt;span class="n">ptr&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">ptr&lt;/span>&lt;span class="o">-&amp;gt;&lt;/span>&lt;span class="n">do_something&lt;/span>&lt;span class="p">();&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// عند الخروج من النطاق (Scope)، يتم تدمير ptr وتحرير Resource
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kt">int&lt;/span> &lt;span class="nf">main&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">unique_ptr&lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="n">Resource&lt;/span>&lt;span class="o">&amp;gt;&lt;/span> &lt;span class="n">my_ptr&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">make_unique&lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="n">Resource&lt;/span>&lt;span class="o">&amp;gt;&lt;/span>&lt;span class="p">();&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// process_resource(my_ptr); // خطأ: لا يمكن النسخ
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="n">process_resource&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">move&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">my_ptr&lt;/span>&lt;span class="p">));&lt;/span> &lt;span class="c1">// نقل الملكية
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="o">!&lt;/span>&lt;span class="n">my_ptr&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">cout&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="s">&amp;#34;my_ptr is now empty.&lt;/span>&lt;span class="se">\n&lt;/span>&lt;span class="s">&amp;#34;&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>يوضح مخطط Mermaid التالي مفهوم نقل الملكية باستخدام &lt;code>std::move&lt;/code>.&lt;/p>
&lt;div class="mermaid">graph LR
subgraph "قبل std::move"
A["unique_ptr (ptr1)"] -->|"يمتلك"| B["ذاكرة الكومة (كائن)"]
end
subgraph "بعد std::move"
C["unique_ptr (ptr1)"] -.->|"فارغ (nullptr)"| D["nullptr"]
E["unique_ptr (ptr2)"] -->|"يمتلك"| F["ذاكرة الكومة (كائن)"]
end&lt;/div>
&lt;h3 id="23-تنفيذ-حاذف-مخصص-custom-deleter">2.3 تنفيذ حاذف مخصص (Custom Deleter)
&lt;/h3>&lt;p>عند تغليف واجهات برمجة التطبيقات القديمة (Legacy APIs) الخاصة بلغة C (مثل &lt;code>FILE*&lt;/code> أو مآخذ التوصيل Sockets)، نحتاج إلى استدعاء دالة غير &lt;code>delete&lt;/code> (مثل &lt;code>fclose&lt;/code>) لتحرير الذاكرة. يتيح &lt;code>std::unique_ptr&lt;/code> تحديد حاذف مخصص كمعلمة قالب ثانية (Template Parameter).&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;span class="lnt">16
&lt;/span>&lt;span class="lnt">17
&lt;/span>&lt;span class="lnt">18
&lt;/span>&lt;span class="lnt">19
&lt;/span>&lt;span class="lnt">20
&lt;/span>&lt;span class="lnt">21
&lt;/span>&lt;span class="lnt">22
&lt;/span>&lt;span class="lnt">23
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-cpp" data-lang="cpp">&lt;span class="line">&lt;span class="cl">&lt;span class="cp">#include&lt;/span> &lt;span class="cpf">&amp;lt;cstdio&amp;gt;&lt;/span>&lt;span class="cp">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp">#include&lt;/span> &lt;span class="cpf">&amp;lt;memory&amp;gt;&lt;/span>&lt;span class="cp">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp">&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// كائن دالي (Functor) للحاذف المخصص
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="k">struct&lt;/span> &lt;span class="nc">FileDeleter&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kt">void&lt;/span> &lt;span class="nf">operator&lt;/span>&lt;span class="p">()(&lt;/span>&lt;span class="n">FILE&lt;/span>&lt;span class="o">*&lt;/span> &lt;span class="n">fp&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="k">const&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">fp&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">cout&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="s">&amp;#34;Closing file.&lt;/span>&lt;span class="se">\n&lt;/span>&lt;span class="s">&amp;#34;&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">fclose&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">fp&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">};&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">using&lt;/span> &lt;span class="n">UniqueFile&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">unique_ptr&lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="n">FILE&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">FileDeleter&lt;/span>&lt;span class="o">&amp;gt;&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kt">int&lt;/span> &lt;span class="nf">main&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">UniqueFile&lt;/span> &lt;span class="n">file&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">fopen&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;test.txt&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s">&amp;#34;w&amp;#34;&lt;/span>&lt;span class="p">));&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">file&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">fputs&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;Hello, Smart Pointers!&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">file&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">get&lt;/span>&lt;span class="p">());&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// عند انتهاء النطاق، يتم استدعاء FileDeleter وبالتالي fclose
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="k">return&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>إذا استخدمنا مؤشر دالة أو تعبير لامبدا (Lambda) كحاذف مخصص، فقد يزداد حجم &lt;code>unique_ptr&lt;/code>، ولكن استخدام كائن دالي عديم الحالة (Stateless Functor) كما هو موضح أعلاه يحافظ على الحجم ليكون مساويًا للمؤشر الخام بفضل &lt;strong>EBCO (Empty Base Class Optimization)&lt;/strong> في C++ أو السمة &lt;code>[[no_unique_address]]&lt;/code> في C++20 (مما يحافظ على التكلفة الصفرية).&lt;/p>
&lt;h2 id="3-stdshared_ptr-الملكية-المشتركة-وكتلة-التحكم">3. &lt;code>std::shared_ptr&lt;/code>: الملكية المشتركة وكتلة التحكم
&lt;/h2>&lt;p>&lt;code>std::shared_ptr&lt;/code> هو مؤشر ذكي يسمح لعدة مؤشرات بمشاركة ملكية نفس الكائن. يتم تحرير الكائن المُدار فقط عندما يتم تدمير آخر &lt;code>shared_ptr&lt;/code> يشير إليه.&lt;/p>
&lt;h3 id="31-البنية-الداخلية-كتلة-التحكم-control-block">3.1 البنية الداخلية: كتلة التحكم (Control Block)
&lt;/h3>&lt;p>بالإضافة إلى المؤشر الذي يشير إلى الكائن المُدار، يخصص &lt;code>std::shared_ptr&lt;/code> بيانات وصفية (Metadata) تسمى &lt;strong>كتلة التحكم (Control Block)&lt;/strong> على الكومة لمشاركتها. تتضمن كتلة التحكم المعلومات التالية:&lt;/p>
&lt;ol>
&lt;li>&lt;strong>العد القوي (Strong Count)&lt;/strong>: عدد مؤشرات &lt;code>shared_ptr&lt;/code> التي تمتلك الكائن. عندما يصبح هذا العدد 0، يتم تدمير الكائن.&lt;/li>
&lt;li>&lt;strong>العد الضعيف (Weak Count)&lt;/strong>: عدد مؤشرات &lt;code>weak_ptr&lt;/code> التي تراقب الكائن. عندما يصبح كل من العد القوي والعد الضعيف 0، يتم تحرير كتلة التحكم نفسها.&lt;/li>
&lt;li>&lt;strong>الحاذف المخصص والمُخصص (Custom Deleter &amp;amp; Allocator)&lt;/strong> (إذا تم تحديدهما).&lt;/li>
&lt;/ol>
&lt;div class="mermaid">graph TD
A["std::shared_ptr&lt;T> (sp1)"] -->|"مؤشر إلى T"| B["الكائن المُدار (T)"]
A -->|"مؤشر إلى كتلة التحكم"| C["كتلة التحكم"]
D["std::shared_ptr&lt;T> (sp2)"] -->|"مؤشر إلى T"| B
D -->|"مؤشر إلى كتلة التحكم"| C
C -->|"يحذف"| B
C -.->|"العد القوي: 2"| E["العد القوي"]
C -.->|"العد الضعيف: 0"| F["العد الضعيف"]
C -.->|"حاذف مخصص"| G["الحاذف"]&lt;/div>
&lt;p>لهذا السبب، يكون حجم الكائن &lt;code>std::shared_ptr&lt;/code> نفسه عادةً ضعف حجم المؤشر الخام (مؤشر للكائن المُدار، ومؤشر لكتلة التحكم).&lt;/p>
&lt;h3 id="32-الأداء-والعمليات-الذرية-atomic-operations">3.2 الأداء والعمليات الذرية (Atomic Operations)
&lt;/h3>&lt;p>يتم تنفيذ عداد المراجع داخل كتلة التحكم كـ &lt;strong>عمليات ذرية (Atomic Operations)&lt;/strong> لضمان زيادته ونقصانه بأمان في البيئات متعددة الخيوط (Multithreaded).&lt;/p>
&lt;p>في معمارية x86/x64، تُستخدم تعليمات ذرية مثل &lt;code>lock xadd&lt;/code> لزيادة أو إنقاص عداد المراجع. يصاحب ذلك تكلفة إضافية (Overhead) تبلغ عشرات دورات المعالج مقارنة بجمع الأعداد الصحيحة العادية. وبالتالي، فإن تمرير &lt;code>shared_ptr&lt;/code> بالقيم (Pass by Value) إلى دالة سيؤدي إلى زيادة ونقصان ذري في كل عملية نسخ، مما يؤدي إلى تدهور الأداء.&lt;/p>
&lt;p>&lt;strong>أفضل الممارسات&lt;/strong>: عند تمرير &lt;code>shared_ptr&lt;/code> إلى دالة، ما لم تكن هناك حاجة لمشاركة الملكية، يجب تمريره كمرجع ثابت &lt;code>const std::shared_ptr&amp;lt;T&amp;gt;&amp;amp;&lt;/code>، أو تمرير المؤشر الخام/المرجع بدلاً من ذلك.&lt;/p>
&lt;h3 id="33-stdmake_shared-مقابل-new">3.3 &lt;code>std::make_shared&lt;/code> مقابل &lt;code>new&lt;/code>
&lt;/h3>&lt;p>عند إنشاء &lt;code>shared_ptr&lt;/code>، يجب استخدام &lt;code>std::make_shared&lt;/code> قدر الإمكان. هناك سببان مهمان لذلك:&lt;/p>
&lt;ol>
&lt;li>&lt;strong>تحسين تخصيص الذاكرة&lt;/strong>:
عند استخدام &lt;code>new&lt;/code>، يتم إجراء تخصيصين للذاكرة على الكومة: تخصيص للكائن نفسه وتخصيص لكتلة التحكم. بينما يتيح &lt;code>std::make_shared&lt;/code> تخصيص كتلة ذاكرة واحدة كبيرة تشمل كليهما في عملية تخصيص واحدة، مما يحسن كفاءة الذاكرة المخبئية (Cache).&lt;/li>
&lt;li>&lt;strong>أمان الاستثناءات (Exception Safety)&lt;/strong>:
في معايير C++ قبل C++17، لم يكن ترتيب تقييم وسائط الدالة محددًا، لذا إذا تم تخصيص مؤشر باستخدام &lt;code>new&lt;/code> وحدث استثناء أثناء تقييم وسائط أخرى قبل تمريره إلى دالة بناء &lt;code>shared_ptr&lt;/code>، كان هناك خطر تسرب الذاكرة. أداة &lt;code>make_shared&lt;/code> تتجنب هذه المشكلة تماماً.&lt;/li>
&lt;/ol>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;span class="lnt">4
&lt;/span>&lt;span class="lnt">5
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-cpp" data-lang="cpp">&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// الطريقة التي يجب تجنبها (تخصيص الذاكرة مرتين)
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">shared_ptr&lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="n">MyClass&lt;/span>&lt;span class="o">&amp;gt;&lt;/span> &lt;span class="n">ptr1&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="k">new&lt;/span> &lt;span class="n">MyClass&lt;/span>&lt;span class="p">());&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// الطريقة الموصى بها (تخصيص الذاكرة مرة واحدة)
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">shared_ptr&lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="n">MyClass&lt;/span>&lt;span class="o">&amp;gt;&lt;/span> &lt;span class="n">ptr2&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">make_shared&lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="n">MyClass&lt;/span>&lt;span class="o">&amp;gt;&lt;/span>&lt;span class="p">();&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h2 id="4-stdweak_ptr-حل-مشكلة-المراجع-الدائرية-والمراقبة">4. &lt;code>std::weak_ptr&lt;/code>: حل مشكلة المراجع الدائرية والمراقبة
&lt;/h2>&lt;p>تحتوي الملكية المشتركة على نقطة ضعف قاتلة تُعرف باسم &amp;ldquo;المراجع الدائرية&amp;rdquo; (Circular References). إذا كان الكائن A والكائن B يشيران إلى بعضهما البعض باستخدام &lt;code>shared_ptr&lt;/code>، فسيظل العد القوي لكل منهما 1 على الأقل، ولن يصبح 0 أبدًا حتى ينتهي البرنامج، مما يؤدي إلى تسرب الذاكرة.&lt;/p>
&lt;div class="mermaid">graph TD
subgraph "مرجع دائري (تسرب الذاكرة)"
A["الكائن A"] -->|"shared_ptr (Strong=1)"| B["الكائن B"]
B -->|"shared_ptr (Strong=1)"| A
end&lt;/div>
&lt;h3 id="41-كسر-الدائرة-بواسطة-stdweak_ptr">4.1 كسر الدائرة بواسطة &lt;code>std::weak_ptr&lt;/code>
&lt;/h3>&lt;p>التي تحل هذه المشكلة هي &lt;code>std::weak_ptr&lt;/code>. يتم إنشاء &lt;code>weak_ptr&lt;/code> من &lt;code>shared_ptr&lt;/code> ويشير إلى الكائن، ولكنه &lt;strong>لا يزيد من العد القوي&lt;/strong>. بدلاً من ذلك، يزيد من العد الضعيف. يتيح هذا &amp;ldquo;مراقبة&amp;rdquo; الكائن دون امتلاكه.&lt;/p>
&lt;div class="mermaid">graph TD
subgraph "كسر المرجع الدائري"
C["الكائن A"] -->|"shared_ptr (Strong=1)"| D["الكائن B"]
D -.->|"weak_ptr (Weak=1)"| C
end&lt;/div>
&lt;h3 id="42-الوصول-الآمن-عبر-التابع-lock">4.2 الوصول الآمن عبر التابع &lt;code>lock()&lt;/code>
&lt;/h3>&lt;p>لا يمتلك &lt;code>weak_ptr&lt;/code> عوامل تشغيل للوصول المباشر إلى الكائن (مثل &lt;code>-&amp;gt;&lt;/code> أو &lt;code>*&lt;/code>). ويرجع ذلك إلى احتمال أن يكون الكائن المستهدف قد تم تدميره بالفعل. للوصول بأمان، نقوم باستدعاء التابع &lt;code>lock()&lt;/code> للحصول مؤقتاً على &lt;code>shared_ptr&lt;/code>.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;span class="lnt">16
&lt;/span>&lt;span class="lnt">17
&lt;/span>&lt;span class="lnt">18
&lt;/span>&lt;span class="lnt">19
&lt;/span>&lt;span class="lnt">20
&lt;/span>&lt;span class="lnt">21
&lt;/span>&lt;span class="lnt">22
&lt;/span>&lt;span class="lnt">23
&lt;/span>&lt;span class="lnt">24
&lt;/span>&lt;span class="lnt">25
&lt;/span>&lt;span class="lnt">26
&lt;/span>&lt;span class="lnt">27
&lt;/span>&lt;span class="lnt">28
&lt;/span>&lt;span class="lnt">29
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-cpp" data-lang="cpp">&lt;span class="line">&lt;span class="cl">&lt;span class="cp">#include&lt;/span> &lt;span class="cpf">&amp;lt;iostream&amp;gt;&lt;/span>&lt;span class="cp">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp">#include&lt;/span> &lt;span class="cpf">&amp;lt;memory&amp;gt;&lt;/span>&lt;span class="cp">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp">&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">class&lt;/span> &lt;span class="nc">Node&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">public&lt;/span>&lt;span class="o">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">string&lt;/span> &lt;span class="n">name&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">shared_ptr&lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="n">Node&lt;/span>&lt;span class="o">&amp;gt;&lt;/span> &lt;span class="n">next&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">weak_ptr&lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="n">Node&lt;/span>&lt;span class="o">&amp;gt;&lt;/span> &lt;span class="n">prev&lt;/span>&lt;span class="p">;&lt;/span> &lt;span class="c1">// استخدام weak_ptr لمنع المرجع الدائري
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">Node&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="k">const&lt;/span> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">string&lt;/span>&lt;span class="o">&amp;amp;&lt;/span> &lt;span class="n">n&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">:&lt;/span> &lt;span class="n">name&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">n&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">cout&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="s">&amp;#34;Created &amp;#34;&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="n">name&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="s">&amp;#34;&lt;/span>&lt;span class="se">\n&lt;/span>&lt;span class="s">&amp;#34;&lt;/span>&lt;span class="p">;&lt;/span> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">~&lt;/span>&lt;span class="n">Node&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="p">{&lt;/span> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">cout&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="s">&amp;#34;Destroyed &amp;#34;&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="n">name&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="s">&amp;#34;&lt;/span>&lt;span class="se">\n&lt;/span>&lt;span class="s">&amp;#34;&lt;/span>&lt;span class="p">;&lt;/span> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">};&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kt">int&lt;/span> &lt;span class="nf">main&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">auto&lt;/span> &lt;span class="n">nodeA&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">make_shared&lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="n">Node&lt;/span>&lt;span class="o">&amp;gt;&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;A&amp;#34;&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">auto&lt;/span> &lt;span class="n">nodeB&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">make_shared&lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="n">Node&lt;/span>&lt;span class="o">&amp;gt;&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;B&amp;#34;&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">nodeA&lt;/span>&lt;span class="o">-&amp;gt;&lt;/span>&lt;span class="n">next&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">nodeB&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">nodeB&lt;/span>&lt;span class="o">-&amp;gt;&lt;/span>&lt;span class="n">prev&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">nodeA&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// الحصول على shared_ptr من weak_ptr للوصول
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="k">auto&lt;/span> &lt;span class="n">locked_prev&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">nodeB&lt;/span>&lt;span class="o">-&amp;gt;&lt;/span>&lt;span class="n">prev&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">lock&lt;/span>&lt;span class="p">())&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">cout&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="s">&amp;#34;Node B&amp;#39;s prev is &amp;#34;&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="n">locked_prev&lt;/span>&lt;span class="o">-&amp;gt;&lt;/span>&lt;span class="n">name&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="s">&amp;#34;&lt;/span>&lt;span class="se">\n&lt;/span>&lt;span class="s">&amp;#34;&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span> &lt;span class="k">else&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">cout&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="s">&amp;#34;Node B&amp;#39;s prev is already destroyed.&lt;/span>&lt;span class="se">\n&lt;/span>&lt;span class="s">&amp;#34;&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">;&lt;/span> &lt;span class="c1">// يتم تدمير nodeA و nodeB بشكل صحيح
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h2 id="5-قيود-الملكية-المشتركة-في-البيئات-متعددة-الخيوط">5. قيود الملكية المشتركة في البيئات متعددة الخيوط
&lt;/h2>&lt;p>غالبًا ما يُساء فهم أمان الخيوط (Thread Safety) الخاص بـ &lt;code>shared_ptr&lt;/code>. &amp;ldquo;تحديث عداد المراجع داخل كتلة التحكم يعتبر آمنًا للخيوط&amp;rdquo;، ولكن &amp;ldquo;القراءة والكتابة لنفس الكائن &lt;code>shared_ptr&lt;/code> بحد ذاته ليست آمنة للخيوط&amp;rdquo;.&lt;/p>
&lt;ul>
&lt;li>&lt;strong>العمليات الآمنة&lt;/strong>: عدة خيوط تقوم كل منها بقراءة وكتابة &lt;em>نسختها الخاصة&lt;/em> من &lt;code>shared_ptr&lt;/code> (على الرغم من أنها تشترك في نفس كتلة التحكم).&lt;/li>
&lt;li>&lt;strong>سباق البيانات (خطير)&lt;/strong>: عدة خيوط تقوم في وقت واحد بالقراءة والكتابة &lt;em>لنفس الكائن&lt;/em> &lt;code>shared_ptr&lt;/code> بالظبط.&lt;/li>
&lt;/ul>
&lt;p>إذا كانت هناك حاجة لمشاركة نفس النسخة عبر خيوط متعددة، يجب استخدام &lt;code>std::atomic&amp;lt;std::shared_ptr&amp;lt;T&amp;gt;&amp;gt;&lt;/code> (في C++20) أو حمايته باستخدام كائن قفل (Mutex) &lt;code>std::mutex&lt;/code>.&lt;/p>
&lt;h2 id="6-الصياغة-الرياضية-لعداد-المراجع">6. الصياغة الرياضية لعداد المراجع
&lt;/h2>&lt;p>يمكن التعبير رياضياً عن انتقال حالة دورة الحياة في كتلة التحكم على النحو التالي.
بفرض أن العد القوي في الوقت $t$ هو $S(t)$، والعد الضعيف هو $W(t)$.&lt;/p>
&lt;p>الحالة الأولية (مباشرة بعد &lt;code>make_shared&lt;/code>):
&lt;/p>
$$ S(0) = 1, \quad W(0) = 0 $$
&lt;p>عند حدوث عملية نسخ (تكرار لـ &lt;code>shared_ptr&lt;/code>):
&lt;/p>
$$ S(t_{next}) = S(t) + 1 $$
&lt;p>شرط تدمير الكائن المُدار (Managed Object):
&lt;/p>
$$ \lim_{t \to t_d} S(t) = 0 $$
&lt;p>شرط تحرير كتلة التحكم (Control Block) نفسها من الذاكرة:
&lt;/p>
$$ S(t) = 0 \quad \land \quad W(t) = 0 $$
&lt;p>
أي بمعنى آخر،
&lt;/p>
$$ S(t) + W(t) = 0 $$
&lt;p>كما توضح هذه المعادلات، طالما أن &lt;code>weak_ptr&lt;/code> مستمر في الوجود ($W(t) > 0$)، فستظل مساحة الذاكرة الصغيرة المخصصة لكتلة التحكم محجوزة حتى لو تم تدمير الكائن المُدار. في بعض الحالات، يُعتبر هذا هو العيب الوحيد لـ &lt;code>make_shared&lt;/code> (نظراً لدمج ذاكرة الكائن المُدار مع كتلة التحكم، إذا بقي مرجع ضعيف، فإن مساحة الذاكرة الكبيرة المخصصة للكائن المُدار لن تُعاد إلى النظام). ولكن في العادة، تفوق الفوائد المتعلقة بالأداء لـ &lt;code>make_shared&lt;/code> هذا العيب بكثير.&lt;/p>
&lt;h2 id="7-الخاتمة">7. الخاتمة
&lt;/h2>&lt;p>لم تعد إدارة الذاكرة في C++ الحديثة تتطلب التعامل اليدوي باستخدام &lt;code>new&lt;/code>/&lt;code>delete&lt;/code>.&lt;/p>
&lt;ol>
&lt;li>بشكل افتراضي، استخدم دائمًا &lt;strong>&lt;code>std::unique_ptr&lt;/code>&lt;/strong> لدمج الملكية الواضحة في تصميمك مع الاستفادة من ميزة التكلفة الصفرية.&lt;/li>
&lt;li>استخدم &lt;strong>&lt;code>std::shared_ptr&lt;/code>&lt;/strong> فقط عندما تحتاج حقًا إلى مشاركة دورة الحياة بين عدة مالكين، واستخدم &lt;code>std::make_shared&lt;/code> للإنشاء.&lt;/li>
&lt;li>استخدم &lt;strong>&lt;code>std::weak_ptr&lt;/code>&lt;/strong> في هياكل البيانات التي قد تسبب حلقات (مراجع دائرية) أو في تنفيذ نمط المراقب (Observer Pattern) لمنع تسرب الذاكرة بشكل استباقي.&lt;/li>
&lt;/ol>
&lt;p>من خلال الفهم العميق للمؤشرات الذكية واستخدامها في المكان المناسب، يصبح من الممكن بناء بنية برمجية آمنة وقوية دون التضحية بأي شيء من أداء C++.&lt;/p></description></item></channel></rss>