🎯 مقدمة: ليش Multithreading؟ وليش مهم في C++ تحديدًا؟
في الماضي كانت المعالجات نواة واحدة…
يعني مهما كتبت عمليات في برنامجك، كلها رح تشتغل بشكل خطّي.
لكن اليوم:
- لابتوبك فيه 4 أو 8 أنوية
- سيرفرات البرمجة فيه 32 و 64 و 128 نواة
- حتى موبايلك فيه 8 أنوية
فالسؤال:
ليش برنامجك ما يستفيد من الأنوية؟
ليش تترك 90% من قدرة الكمبيوتر نايمة؟
Multithreading يسمح لك:
✔ تقسم حمل العمل بين الأنوية
✔ تسريع البرامج الثقيلة
✔ تشغيل مهام بالخلفية بدون تجميد البرنامج
✔ المعالجة المتوازية Parallel Processing
✔ بناء سيرفرات High-Concurrency
✔ التعامل مع بيانات ضخمة بسرعة كبيرة
✔ تشغيل خوارزميات تنافس الزمن (مثل AI / ML)
ولأن C++ قريبة من الهاردوير…
فهي واحدة من أقوى لغات العالم في multithreading على الإطلاق.
──────────────────────────────────────────────
🧠 الفصل الأول: ما هو الـ Thread؟
الـ Thread هو خط تنفيذي مستقل داخل نفس البرنامج.
بتشارك الـ memory + الكود + البيانات…
لكن كل Thread عنده stack خاص فيه.
📌 شكل البرنامج في الذاكرة:
| الجزء | Shared؟ |
|---|---|
| heap | ✔ تشاركي |
| global variables | ✔ تشاركي |
| code | ✔ تشاركي |
| stack | ❌ لكل Thread واحد |
وهذا اللي يسبب مشاكل الـ race conditions.
🚀 الفصل الثاني: إنشاء Thread باستخدام std::thread
📦 مثال بسيط:
#include <iostream>
#include <thread>
using namespace std;
void run() {
cout << "Thread is running...\n";
}
int main() {
thread t(run);
t.join();
}
📌 شرح:
thread t(run);→ إنشاء خيط وتنفيذ دالة runt.join();→ انتظار انتهاء الخيط
لو شلت join() البرنامج قد ينتهي قبل إنهاء الخيط → كارثة!
🧩 تمرير بارامترات إلى Thread
void greet(string name, int times) {
for (int i = 0; i < times; i++)
cout << "Hello " << name << endl;
}
int main() {
thread t(greet, "Mohammad", 5);
t.join();
}
⚡ استخدام Lambda Functions
thread t([](){
cout << "Running lambda thread.\n";
});
t.join();
🧨 الفصل الثالث: مشكلة الـ Race Conditions
المصيبة اللي بتخرب multithreading إذا ما فهمتها.
مثال خطير:
int counter = 0;
void add() {
for (int i = 0; i < 100000; i++)
counter++;
}
int main() {
thread t1(add);
thread t2(add);
t1.join(); t2.join();
cout << counter << endl;
}
النتيجة “عشوائية”:
130000
182000
200000
150430
ليش؟
- لأن العمليّة
counter++مش عملية واحدة
هي 3 عمليات:
- load
- increment
- store
تخيل اتنين Threads يعملوها بنفس الوقت؟
برنامجك يصير في “حرب على المتغيّر”.
🔒 الفصل الرابع: حلّ المشكلة باستخدام mutex
ما هو Mutex؟
هو “قفل” يمنع أكثر من Thread من لمس نفس الذاكرة.
mutex m;
void add() {
for (int i = 0; i < 100000; i++) {
m.lock();
counter++;
m.unlock();
}
}
لكن هذا الشكل خطير…
لو حدث خطأ قبل unlock → deadlock.
لذلك نستخدم:
lock_guard<mutex> lock(m);
يفتح القفل عند الدخول ويغلقه تلقائيًا عند الخروج (RAII).
⭐ حماية increment بشكل صحيح
mutex m;
void add() {
for (int i = 0; i < 100000; i++) {
lock_guard<mutex> lock(m);
counter++;
}
}
⚡ الفصل الخامس: أنواع Mutex المتقدمة
1. recursive_mutex
يسمح لنفس الخيط يعمل lock مرتين أو أكثر بدون مشاكل.
2. timed_mutex
يسمح بـ lock لمدة معينة:
timed_mutex tm;
if (tm.try_lock_for(chrono::seconds(1))) {
// locked
}
3. shared_mutex
للقراءة المتوازية والكتابة المفردة:
- عدة Threads تستطيع القراءة معًا
- لكن كتابة واحدة فقط
مثال:
shared_mutex sm;
// read
shared_lock<shared_mutex> lock(sm);
// write
unique_lock<shared_mutex> lock(sm);
🧠 الفصل السادس: join vs detach
1. join()
انتظر الخيط لآخره.
2. detach()
الخيط يكمل لوحده بالخلفية.
thread t(backgroundTask);
t.detach();
⚠️ لكنه خطير جدًا:
- ممكن الخيط يكمل بعد انتهاء main → undefined behavior
- أو يتعامل مع memory محذوفة
🎯 الفصل السابع: المعالجة المتوازية Parallelism
Multithreading ≠ Parallelism دائمًا
لكن C++ تسمح بالاثنين.
المثال التالي يقوم بعمل حسابي على 4 Threads:
void compute(int start, int end) {
long long sum = 0;
for (int i = start; i <= end; i++)
sum += i;
cout << "Sum: " << sum << endl;
}
🧩 الفصل الثامن: Deadlocks — القتل الصامت
Deadlock = خيطين ينتظرون بعض للأبد.
مثال قاتل:
mutex m1, m2;
void taskA() {
lock_guard<mutex> lock1(m1);
this_thread::sleep_for(100ms);
lock_guard<mutex> lock2(m2);
}
void taskB() {
lock_guard<mutex> lock2(m2);
this_thread::sleep_for(100ms);
lock_guard<mutex> lock1(m1);
}
الحل؟
استخدم std::scoped_lock
scoped_lock lock(m1, m2);
⚡ الفصل التاسع: atomic variables (بديل عن mutex)
لو عندك عمليات بسيطة جدًا على متغير واحد:
atomic<int> counter = 0;
void add() {
for (int i = 0; i < 100000; i++)
counter++;
}
بدون mutex
بدون قفل
بدون مشاكل
💥 الفصل العاشر: condition_variable — التزامن المتقدم
يستخدم لعمل producer/consumer.
مثال:
queue<int> q;
mutex m;
condition_variable cv;
void producer() {
for (int i = 1; i <= 10; i++) {
{
lock_guard<mutex> lock(m);
q.push(i);
}
cv.notify_one();
}
}
void consumer() {
while (true) {
unique_lock<mutex> lock(m);
cv.wait(lock, []{ return !q.empty(); });
int val = q.front(); q.pop();
cout << "Consumed " << val << endl;
}
}
🔥 الفصل الحادي عشر: بناء Logger متعدّد الخيوط (مشروع عملي)
برنامج Log يكتب سطور إلى ملف من عدة Threads بدون تخريب:
mutex logMutex;
void log(string msg) {
lock_guard<mutex> lock(logMutex);
ofstream file("log.txt", ios::app);
file << msg << endl;
}
🌪 الفصل الثاني عشر: Thread Pool — مستوى الشركات
في التطبيقات الكبيرة، ما بقدر أعمل 10000 Thread.
الحل؟
Thread Pool:
- مجموعة ثابتة من الخيوط
- Queue للمهام
- Workers يسحبون المهام وينفذونها
نموذج بسيط (مختصر):
class ThreadPool {
private:
vector<thread> workers;
queue<function<void()>> tasks;
mutex m;
condition_variable cv;
bool stop = false;
public:
ThreadPool(int count) {
for (int i = 0; i < count; i++)
workers.push_back(thread([this] {
while (true) {
function<void()> task;
{
unique_lock<mutex> lock(m);
cv.wait(lock, [this]{ return stop || !tasks.empty(); });
if (stop && tasks.empty()) return;
task = move(tasks.front());
tasks.pop();
}
task();
}
}));
}
void enqueue(function<void()> func) {
{
lock_guard<mutex> lock(m);
tasks.push(func);
}
cv.notify_one();
}
~ThreadPool() {
{
lock_guard<mutex> lock(m);
stop = true;
}
cv.notify_all();
for (auto& w : workers) w.join();
}
};
🧨 الفصل الثالث عشر: الأخطاء القاتلة في Multithreading
❌ مشاركة متغيرات بدون mutex
❌ Deadlock
❌ استخدام detach بلا سبب
❌ الكتابة على نفس الملف بدون حماية
❌ catch سيء داخل thread يخفي الأخطاء
❌ الاعتماد على sleep() للتزامن
❌ استخدام pointers خطيرة وتغيير الذاكرة أثناء تنفيذ thread
🎯 الخلاصة النهائية
هذا واحد من أعقد وأقوى دروس C++.
Multithreading هو العمود الفقري للتطبيقات الضخمة:
✔ المحاكاة Simulation
✔ AI / ML
✔ السيرفرات
✔ الألعاب
✔ معالجة الصور والفيديو
✔ التطبيقات العلمية
✔ أنظمة التداول
✔ محركات 3D
✔ Desktop Apps
وفهم:
- thread
- mutex
- atomic
- deadlock
- condition_variable
- thread pool
يعني أنك دخلت رسمياً إلى منطقة “مبرمج أنظمة”.
ولو صحلك مقابلة عمل…
هي المفاهيم اللي بيسألوك عنها.


