当前位置: 首页 > news >正文

C++多线程编程入门实战

本文旨在帮助初学者快速理解和跑通C++多线程编程,涵盖从基础概念到实际应用的完整路径。

第一部分:核心概念与准备工作

多线程编程的重要性

在多核处理器成为主流的今天,多线程编程是提高程序性能的关键技术。它允许程序同时执行多个任务,充分利用硬件资源。

C++多线程开发环境配置

  • C++11及以上版本:确保你的编译器支持C++11或更高标准
  • 编译器选项:使用 -std=c++11(或更高)和 -pthread 标志编译
  • 头文件#include <thread>, #include <mutex>, #include <atomic>

初学者建议

  1. 从单线程开始:先实现正确的单线程版本
  2. 理解数据竞争:多个线程同时访问共享数据的危险性
  3. 掌握同步机制:互斥锁、原子操作等
  4. 避免死锁:注意锁的获取和释放顺序

第二部分:基础代码示例

示例1:单线程 vs 多线程基础

a) 单线程版本
#include <iostream>
#include <chrono>
#include <thread>// 模拟耗时任务
void task(int id, int duration_ms) {std::this_thread::sleep_for(std::chrono::milliseconds(duration_ms));std::cout << "Task " << id << " completed on thread: " << std::this_thread::get_id() << std::endl;
}int main() {auto start = std::chrono::high_resolution_clock::now();// 顺序执行任务task(1, 100);task(2, 150);task(3, 200);auto end = std::chrono::high_resolution_clock::now();auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(end - start);std::cout << "Single-threaded execution time: " << duration.count() << " ms" << std::endl;return 0;
}

编译命令:

g++ -std=c++11 -pthread single_thread.cpp -o single_thread
b) 多线程版本
#include <iostream>
#include <chrono>
#include <thread>
#include <vector>void task(int id, int duration_ms) {std::this_thread::sleep_for(std::chrono::milliseconds(duration_ms));std::cout << "Task " << id << " completed on thread: " << std::this_thread::get_id() << std::endl;
}int main() {auto start = std::chrono::high_resolution_clock::now();// 创建线程数组std::vector<std::thread> threads;// 启动多个线程threads.emplace_back(task, 1, 100);threads.emplace_back(task, 2, 150);threads.emplace_back(task, 3, 200);// 等待所有线程完成for (auto& t : threads) {t.join();}auto end = std::chrono::high_resolution_clock::now();auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(end - start);std::cout << "Multi-threaded execution time: " << duration.count() << " ms" << std::endl;return 0;
}

编译命令:

g++ -std=c++11 -pthread multi_thread.cpp -o multi_thread

关键点说明:

  • std::thread 创建新线程
  • emplace_back 直接在线程向量中构造线程对象
  • join() 等待线程执行完成
  • 输出中线程ID不同,表明任务在不同线程执行

示例2:数据竞争与互斥锁解决方案

a) 存在数据竞争的代码
#include <iostream>
#include <thread>
#include <vector>int shared_counter = 0;void increment_without_lock(int iterations) {for (int i = 0; i < iterations; ++i) {shared_counter++; // 非原子操作,存在数据竞争}
}int main() {const int iterations = 100000;std::vector<std::thread> threads;// 创建多个线程同时增加计数器for (int i = 0; i < 5; ++i) {threads.emplace_back(increment_without_lock, iterations);}for (auto& t : threads) {t.join();}std::cout << "Expected: " << 5 * iterations << std::endl;std::cout << "Actual: " << shared_counter << std::endl;std::cout << "Data race occurred: " << (shared_counter != 5 * iterations ? "YES" : "NO") << std::endl;return 0;
}
b) 使用互斥锁的正确版本
#include <iostream>
#include <thread>
#include <vector>
#include <mutex>int shared_counter = 0;
std::mutex counter_mutex;void increment_with_lock(int iterations) {for (int i = 0; i < iterations; ++i) {std::lock_guard<std::mutex> lock(counter_mutex);shared_counter++;}
}void increment_with_try_lock(int iterations) {for (int i = 0; i < iterations; ++i) {std::unique_lock<std::mutex> lock(counter_mutex, std::try_to_lock);if (lock.owns_lock()) {shared_counter++;} else {// 处理获取锁失败的情况std::this_thread::yield();}}
}int main() {const int iterations = 100000;std::vector<std::thread> threads;// 测试 lock_guardshared_counter = 0;for (int i = 0; i < 5; ++i) {threads.emplace_back(increment_with_lock, iterations);}for (auto& t : threads) {t.join();}std::cout << "Using lock_guard - Expected: " << 5 * iterations << std::endl;std::cout << "Using lock_guard - Actual: " << shared_counter << std::endl;// 清空线程向量threads.clear();// 测试 unique_lock with try_lockshared_counter = 0;for (int i = 0; i < 5; ++i) {threads.emplace_back(increment_with_try_lock, iterations);}for (auto& t : threads) {t.join();}std::cout << "Using unique_lock(try_lock) - Expected: " << 5 * iterations << std::endl;std::cout << "Using unique_lock(try_lock) - Actual: " << shared_counter << std::endl;return 0;
}

关键点说明:

  • std::mutex 提供基本的互斥功能
  • std::lock_guard RAII风格,自动管理锁的生命周期
  • std::unique_lock 更灵活,支持延迟锁定、尝试锁定等

示例3:原子操作 - 无锁解决方案

#include <iostream>
#include <thread>
#include <vector>
#include <atomic>std::atomic<int> atomic_counter(0);void increment_atomic(int iterations) {for (int i = 0; i < iterations; ++i) {atomic_counter++; // 原子操作,无数据竞争}
}int main() {const int iterations = 100000;std::vector<std::thread> threads;for (int i = 0; i < 5; ++i) {threads.emplace_back(increment_atomic, iterations);}for (auto& t : threads) {t.join();}std::cout << "Atomic counter - Expected: " << 5 * iterations << std::endl;std::cout << "Atomic counter - Actual: " << atomic_counter << std::endl;return 0;
}

示例4:条件变量实现生产者-消费者模式

#include <iostream>
#include <thread>
#include <queue>
#include <mutex>
#include <condition_variable>
#include <chrono>std::queue<int> data_queue;
std::mutex queue_mutex;
std::condition_variable queue_condvar;
const int MAX_ITEMS = 10;void producer(int id) {for (int i = 0; i < 5; ++i) {std::this_thread::sleep_for(std::chrono::milliseconds(100));std::unique_lock<std::mutex> lock(queue_mutex);// 等待队列有空间queue_condvar.wait(lock, []{ return data_queue.size() < MAX_ITEMS; });int data = id * 100 + i;data_queue.push(data);std::cout << "Producer " << id << " produced: " << data << std::endl;lock.unlock();queue_condvar.notify_all(); // 通知消费者}
}void consumer(int id) {for (int i = 0; i < 3; ++i) {std::unique_lock<std::mutex> lock(queue_mutex);// 等待队列有数据queue_condvar.wait(lock, []{ return !data_queue.empty(); });int data = data_queue.front();data_queue.pop();std::cout << "Consumer " << id << " consumed: " << data << std::endl;lock.unlock();queue_condvar.notify_all(); // 通知生产者}
}int main() {std::vector<std::thread> producers;std::vector<std::thread> consumers;// 创建2个生产者和3个消费者for (int i = 0; i < 2; ++i) {producers.emplace_back(producer, i + 1);}for (int i = 0; i < 3; ++i) {consumers.emplace_back(consumer, i + 1);}for (auto& t : producers) {t.join();}for (auto& t : consumers) {t.join();}return 0;
}

第三部分:进阶主题与最佳实践

1. 线程池基础实现

#include <iostream>
#include <thread>
#include <vector>
#include <queue>
#include <functional>
#include <mutex>
#include <condition_variable>
#include <future>class ThreadPool {
public:ThreadPool(size_t num_threads) : stop(false) {for (size_t i = 0; i < num_threads; ++i) {workers.emplace_back([this] {for (;;) {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();}});}}template<class F, class... Args>auto enqueue(F&& f, Args&&... args) -> std::future<typename std::result_of<F(Args...)>::type> {using return_type = typename std::result_of<F(Args...)>::type;auto task = std::make_shared<std::packaged_task<return_type()>>(std::bind(std::forward<F>(f), std::forward<Args>(args)...));std::future<return_type> res = task->get_future();{std::unique_lock<std::mutex> lock(queue_mutex);if(stop)throw std::runtime_error("enqueue on stopped ThreadPool");tasks.emplace([task](){ (*task)(); });}condition.notify_one();return res;}~ThreadPool() {{std::unique_lock<std::mutex> lock(queue_mutex);stop = true;}condition.notify_all();for (std::thread &worker : workers)worker.join();}private:std::vector<std::thread> workers;std::queue<std::function<void()>> tasks;std::mutex queue_mutex;std::condition_variable condition;bool stop;
};// 使用示例
int main() {ThreadPool pool(4);std::vector<std::future<int>> results;for (int i = 0; i < 8; ++i) {results.emplace_back(pool.enqueue([i] {std::this_thread::sleep_for(std::chrono::seconds(1));std::cout << "Task " << i << " executed by thread " << std::this_thread::get_id() << std::endl;return i * i;}));}for (auto&& result : results)std::cout << "Result: " << result.get() << std::endl;return 0;
}

2. 最佳实践总结

  1. 优先使用RAIIstd::lock_guard, std::unique_lock
  2. 避免死锁:按固定顺序获取锁,或使用std::lock同时锁定多个互斥量
  3. 合理使用原子操作:对于简单的计数器,原子操作比互斥锁更高效
  4. 使用条件变量进行线程间通信:避免忙等待
  5. 考虑使用线程池:避免频繁创建销毁线程的开销
  6. 异常安全:确保锁在异常情况下也能正确释放

3. 常见陷阱

  • 数据竞争:未正确同步共享数据的访问
  • 死锁:循环等待资源
  • 活锁:线程不断改变状态但无法进展
  • 优先级反转:低优先级线程持有高优先级线程需要的资源

结语

多线程编程是C++开发中的重要技能,虽然有一定难度,但通过循序渐进的学习和实践,完全可以掌握。建议从简单的示例开始,逐步深入理解同步机制,最终能够设计出高效、安全的并发程序。

http://www.dtcms.com/a/434974.html

相关文章:

  • 个体工商户经营范围网站开发网站建设2018需要什么
  • 泰山派rk3566 sdk编译
  • GAMES101:现代计算机图形学入门(Chapter3 变换)迅猛式学习笔记
  • 0.0 编码基础模板
  • 用哈希表封装unordered_set和unordered_map
  • 有做面食的网站吗企业网络营销策划案
  • 中山做网站长沙营销企业网站建设
  • 江苏模板网站建设h5微场景制作软件
  • VSCode C/C++ 构建任务配置文件 `tasks.json` 全字段深度解析
  • 动力学系统辨识与建模
  • 做微商网站设计成都网站建设冠辰
  • 【1.SpringAI】3.SpringAI 聊天模型的介绍
  • 多模态大语言模型LISA++
  • 数据合规法律体系的宏观框架与实践要点
  • AoT - Attack on Things:A security analysis of IoT firmware updates论文梳理分析
  • 电子商务网站建设基本组成专门做推广的网站吗
  • 抄底券网站怎么做的网络平台建设怎么做
  • 给我一个免费网站吗昆明小程序开发
  • 网站建设需要哪些人员iis发布asp网站
  • 网络安全等级保护测评实施过程
  • SpringBoot + RabbitMQ 消息队列案例
  • PLC_博图系列☞基本指令”S_CU:分配参数并加计数”
  • k8s-pod调度
  • 中国工商做年报网站石家庄seo网站优化公司
  • 帝国CMS作文网题目文学文章wap+pc自适应响应式模板PHP网站源码
  • 邢台移动网站建设费用wordpress获取用户id
  • 网站设计的技能上海哪家做网站关键词排名
  • 酒店网站建设报价详情wordpress %1$s
  • 网站做支付要多少钱做产品代理上哪个网站好
  • RHEL安装