آموزش برنامه نویسی قسمت 15 (thread در زبان C++):

مولتی‌تردینگ یعنی اجرای چند جریان (Thread) به‌صورت همزمان در یک برنامه. هر ترد یک مسیر اجرایی مستقل دارد، اما تمام تردها حافظه‌ی مشترک برنامه (Shared Memory) را به اشتراک می‌گذارند.

مزایا:

  • افزایش سرعت اجرای برنامه‌ها به خصوص در پردازش‌های سنگین.

  • پاسخگویی بهتر برنامه‌های رابط کاربری (UI) و سرویس‌ها.

  • امکان اجرای کارهای مستقل همزمان.

معایب / چالش‌ها:

  • همزمانی دسترسی به منابع مشترک → نیاز به Synchronization.

  • پیچیدگی در طراحی و دیباگ.

  • امکان بروز Deadlock یا Race Condition.


تردها در C++

C++11 به بعد، کلاس std::thread را معرفی کرده که کار با تردها را ساده کرده است.

۲-۱. ایجاد یک ترد ساده

#include <iostream>
#include <thread>

void printMessage() {
    std::cout << "Hello from thread!" << std::endl;
}

int main() {
    std::thread t(printMessage); // ترد جدید ساخته و اجرا شد
    t.join(); // منتظر پایان ترد می‌مانیم
    return 0;
}

توضیح:

  • std::thread t(func) یک ترد جدید اجرا می‌کند.

  • t.join() برنامه اصلی را متوقف می‌کند تا ترد کامل شود.

۲-۲. چند ترد همزمان

#include <iostream>
#include <thread>

void printNumbers(int start, int end) {
    for (int i = start; i <= end; ++i) {
        std::cout << i << " ";
    }
    std::cout << std::endl;
}

int main() {
    std::thread t1(printNumbers, 1, 5);
    std::thread t2(printNumbers, 6, 10);

    t1.join();
    t2.join();

    return 0;
}

خروجی ممکن است متفاوت باشد چون تردها همزمان اجرا می‌شوند و ترتیب چاپ ثابت نیست.

۲-۳. استفاده از داده‌ی مشترک و Mutex

هنگامی که چند ترد می‌خواهند به داده‌ی مشترک دسترسی داشته باشند، باید از Mutex برای جلوگیری از Race Condition استفاده کنیم.

#include <iostream>
#include <thread>
#include <mutex>

int counter = 0;
std::mutex mtx;

void incrementCounter(int times) {
    for (int i = 0; i < times; ++i) {
        mtx.lock();   // ورود به بخش بحرانی
        ++counter;
        mtx.unlock(); // خروج از بخش بحرانی
    }
}

int main() {
    std::thread t1(incrementCounter, 1000);
    std::thread t2(incrementCounter, 1000);

    t1.join();
    t2.join();

    std::cout << "Counter: " << counter << std::endl;
    return 0;
}

توضیح:

  • بدون mtx ممکن بود مقدار counter کمتر از 2000 شود، زیرا دسترسی همزمان باعث Overwrite می‌شود.

  • mutex تضمین می‌کند فقط یک ترد به بخش بحرانی دسترسی دارد.

۲-۴. مثال پیشرفته:

مدلی کلاسیک در مولتی‌تردینگ که در آن یک ترد داده تولید می‌کند و ترد دیگر مصرف می‌کند.

#include <iostream>
#include <thread>
#include <queue>
#include <mutex>
#include <condition_variable>

std::queue<int> dataQueue;
std::mutex mtx;
std::condition_variable cv;
bool finished = false;

void producer(int n) {
    for (int i = 1; i <= n; ++i) {
        std::unique_lock<std::mutex> lock(mtx);
        dataQueue.push(i);
        std::cout << "Produced: " << i << std::endl;
        lock.unlock();
        cv.notify_one(); // اطلاع دادن به مصرف‌کننده
    }
    finished = true;
    cv.notify_one();
}

void consumer() {
    while (true) {
        std::unique_lock<std::mutex> lock(mtx);
        cv.wait(lock, [] { return !dataQueue.empty() || finished; });

        while (!dataQueue.empty()) {
            int val = dataQueue.front();
            dataQueue.pop();
            std::cout << "Consumed: " << val << std::endl;
        }

        if (finished) break;
    }
}

int main() {
    std::thread prod(producer, 10);
    std::thread cons(consumer);

    prod.join();
    cons.join();

    return 0;
}

توضیح:

  • condition_variable باعث می‌شود مصرف‌کننده منتظر تولید داده باشد.

  • Mutex از دسترسی همزمان به صف جلوگیری می‌کند.

  • الگوی کلاسیک تولیدکننده-مصرف‌کننده (Producer-Consumer) را نشان می‌دهد.


قبل از ساختن Thread:

بعد از ساختن Thread:

Telegram: @CaKeegan
Gmail : amidgm2020@gmail.com