C++多线程编程实战:从入门到精通

2025-05发布6次浏览

C++多线程编程是现代软件开发中非常重要的技能之一,它能够显著提高程序的性能和响应速度。本文将从基础概念入手,逐步深入探讨C++多线程编程的核心技术,并通过实际案例帮助读者掌握多线程编程的精髓。


一、多线程编程的基础知识

1. 什么是多线程

多线程是指一个程序同时运行多个执行路径(线程)。每个线程可以独立地执行代码,从而充分利用多核CPU的能力,提升程序的运行效率。

2. C++中的线程支持

自C++11标准起,C++引入了对多线程的支持,主要包括以下核心组件:

  • std::thread:用于创建和管理线程。
  • std::mutexstd::lock_guard:用于解决并发访问时的数据竞争问题。
  • std::condition_variable:用于线程间的同步通信。

3. 线程的基本操作

以下是使用std::thread创建和管理线程的基本步骤:

#include <iostream>
#include <thread>

void threadFunction() {
    std::cout << "This is a thread function." << std::endl;
}

int main() {
    // 创建线程
    std::thread t(threadFunction);

    // 等待线程结束
    if (t.joinable()) {
        t.join();  // 或者使用 t.detach() 让线程独立运行
    }

    return 0;
}

二、线程同步与数据保护

1. 数据竞争与互斥锁

在多线程环境中,多个线程可能同时访问和修改共享资源,导致数据不一致的问题。为了解决这一问题,可以使用互斥锁(Mutex)来保护共享资源。

示例代码:使用std::mutex

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

std::mutex mtx;  // 定义互斥锁
int sharedData = 0;

void increment() {
    for (int i = 0; i < 1000; ++i) {
        std::lock_guard<std::mutex> lock(mtx);  // 自动加锁和解锁
        ++sharedData;
    }
}

int main() {
    std::thread t1(increment);
    std::thread t2(increment);

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

    std::cout << "Shared Data: " << sharedData << std::endl;  // 输出应为2000
    return 0;
}

2. 条件变量

条件变量允许线程在某些条件未满足时进入等待状态,并在条件满足时被唤醒。

示例代码:生产者-消费者模型

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

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

void producer() {
    for (int i = 0; i < 10; ++i) {
        std::unique_lock<std::mutex> lock(mtx);
        dataQueue.push(i);
        lock.unlock();
        cv.notify_one();  // 唤醒消费者
        std::this_thread::sleep_for(std::chrono::milliseconds(500));
    }
    {
        std::unique_lock<std::mutex> lock(mtx);
        done = true;
    }
    cv.notify_all();  // 通知所有消费者任务完成
}

void consumer(int id) {
    while (true) {
        std::unique_lock<std::mutex> lock(mtx);
        cv.wait(lock, [] { return !dataQueue.empty() || done; });
        if (done && dataQueue.empty()) break;
        int value = dataQueue.front();
        dataQueue.pop();
        lock.unlock();
        std::cout << "Consumer " << id << " consumed: " << value << std::endl;
    }
}

int main() {
    std::thread p(producer);
    std::thread c1(consumer, 1);
    std::thread c2(consumer, 2);

    p.join();
    c1.join();
    c2.join();

    return 0;
}

三、高级主题:线程池与任务调度

1. 线程池的概念

线程池是一种优化机制,通过复用一组预先创建的线程来处理多个任务,避免频繁创建和销毁线程带来的开销。

2. 简单线程池实现

以下是一个简单的线程池实现示例:

示例代码:线程池

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

class ThreadPool {
public:
    ThreadPool(size_t threads) : stop(false) {
        for (size_t i = 0; i < threads; ++i) {
            workers.emplace_back([this] {
                while (true) {
                    std::function<void()> task;
                    {
                        std::unique_lock<std::mutex> lock(this->queue_mutex);
                        this->condition.wait(lock, [this] { return this->stop || !this->tasks.empty(); });
                        if (this->stop && this->tasks.empty()) return;
                        task = std::move(this->tasks.front());
                        this->tasks.pop();
                    }
                    task();
                }
            });
        }
    }

    ~ThreadPool() {
        {
            std::unique_lock<std::mutex> lock(queue_mutex);
            stop = true;
        }
        condition.notify_all();
        for (std::thread &worker : workers) worker.join();
    }

    template<class F>
    void enqueue(F&& f) {
        {
            std::unique_lock<std::mutex> lock(queue_mutex);
            if (stop) throw std::runtime_error("enqueue on stopped ThreadPool");
            tasks.emplace(std::forward<F>(f));
        }
        condition.notify_one();
    }

private:
    std::vector<std::thread> workers;
    std::queue<std::function<void()>> tasks;
    std::mutex queue_mutex;
    std::condition_variable condition;
    bool stop;
};

void printNumber(int num) {
    std::cout << "Thread ID: " << std::this_thread::get_id() << ", Number: " << num << std::endl;
}

int main() {
    ThreadPool pool(4);

    for (int i = 0; i < 10; ++i) {
        pool.enqueue([i] { printNumber(i); });
    }

    return 0;
}

四、性能优化与注意事项

1. 减少锁的竞争

过多的锁会降低程序性能,因此需要合理设计程序结构以减少锁的使用频率。例如,可以采用无锁队列或读写锁等技术。

2. 避免死锁

死锁是指两个或多个线程互相等待对方释放资源而陷入僵持状态。可以通过以下方法避免死锁:

  • 按固定的顺序获取锁。
  • 使用超时机制尝试获取锁。