🎯 مقدمة: ليش 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
يعني أنك دخلت رسمياً إلى منطقة “مبرمج أنظمة”.
ولو صحلك مقابلة عمل…
هي المفاهيم اللي بيسألوك عنها.
اكتشاف المزيد من كود التطور
اشترك للحصول على أحدث التدوينات المرسلة إلى بريدك الإلكتروني.


