目录
class 卑微码农:
def __init__(self):
self.技能 = ['能读懂十年前祖传代码', '擅长用Ctrl+C/V搭建世界', '信奉"能跑就别动"的玄学']
self.发量 = 100 # 初始发量
self.咖啡因耐受度 = '极限'
def 修Bug(self, bug):
try:
# 试图用玄学解决问题
if bug.严重程度 == '离谱':
print("这一定是环境问题!")
else:
print("让我看看是谁又没写注释...哦,是我自己。")
except Exception as e:
# 如果try块都救不了,那就...
print("重启一下试试?")
self.发量 -= 1 # 每解决一个bug,头发-1
# 实例化一个我
我 = 卑微码农()
引言
多线程是现代C++的必备技能。现在CPU动不动就多核,不用多线程简直浪费性能。但多线程不好搞,同步、锁、条件变量,一个不小心就死锁或者数据乱了。我早年写服务器,没锁好共享资源,结果用户数据串了,修了一个通宵。这篇文章会帮你少走弯路,学好多线程,写出高效稳定的程序。
第一部分:C++多线程基础

1.1 为什么用多线程?
多线程让程序并发执行任务,比如一个线程处理用户输入,另一个线程跑计算,第三个线程写日志。多核CPU上,线程能并行,提升性能。常见场景:
- 服务器:每个连接一个线程。
- UI程序:主线程画界面,子线程加载数据。
- 计算密集:并行矩阵运算。
但多线程有代价:同步复杂,调试难。我曾用单线程写游戏逻辑,后来改多线程,帧率翻倍,但debug时间也翻倍。
1.2 C++11前的多线程
C++11前,没标准线程库,靠平台API:
- Windows:CreateThread。
- POSIX:pthreads。
这些API麻烦,跨平台还得自己封装。C++11引入<thread>,统一了接口,幸福感暴增。
1.3 C++线程库概览
C++11起,标准库提供:
- <thread>:线程创建、管理。
- <mutex>:锁和同步。
- <condition_variable>:条件等待。
- <future>:异步任务。
- <atomic>:原子操作。
这些工具让我从pthreads的繁琐中解放出来。
第二部分:线程创建与管理

2.1 创建线程
用std::thread创建,传函数或callable对象。
示例:简单线程。
#include <iostream>
#include <thread>
using namespace std;
void worker() {
cout << "Worker thread running" << endl;
}
int main() {
thread t(worker);
t.join(); // 等待线程结束
cout << "Main thread done" << endl;
return 0;
}
输出:Worker thread running Main thread done
注意:
- join():主线程等子线程结束。
- detach():子线程独立跑,结束后自动清理,但不好控制。
- 不调用join/detach:抛std::terminate,程序崩。
我早年忘了join,程序莫名退出,后来加try-catch兜底。
2.2 传递参数
线程函数可带参数,注意生命周期。
示例:
#include <iostream>
#include <thread>
#include <string>
using namespace std;
void worker(const string& msg) {
cout << "Worker got: " << msg << endl;
}
int main() {
string msg = "Hello from main";
thread t(worker, msg); // 拷贝msg
t.join();
return 0;
}
输出:Worker got: Hello from main
若传引用,用std::ref:
void worker(string& msg) {
msg += " modified";
}
int main() {
string msg = "Hello";
thread t(worker, ref(msg));
t.join();
cout << msg << endl; // Hello modified
return 0;
}
2.3 线程ID与硬件并发
std::this_thread::get_id()获取线程ID,thread::hardware_concurrency()估算可用线程数。
示例:
#include <iostream>
#include <thread>
using namespace std;
void worker() {
cout << "Thread ID: " << this_thread::get_id() << endl;
}
int main() {
cout << "Max threads: " << thread::hardware_concurrency() << endl;
thread t1(worker);
thread t2(worker);
t1.join();
t2.join();
return 0;
}
输出(因机器而异):Max threads: 8 Thread ID: 12345 Thread ID: 67890
我用hardware_concurrency()决定线程池大小。
第三部分:同步与互斥

多线程访问共享资源,容易数据竞争。得用锁。
3.1 std::mutex
mutex(互斥锁)确保一次只有一个线程访问资源。
示例:计数器保护。
#include <iostream>
#include <thread>
#include <mutex>
using namespace std;
mutex mtx;
int counter = 0;
void increment(int n) {
for(int i = 0; i < n; ++i) {
mtx.lock();
++counter;
mtx.unlock();
}
}
int main() {
thread t1(increment, 1000);
thread t2(increment, 1000);
t1.join();
t2.join();
cout << "Counter: " << counter << endl; // 2000
return 0;
}
不用锁,counter可能少于2000,因为++不是原子操作。
3.2 RAII锁:std::lock_guard
手动lock/unlock易忘unlock,用lock_guard自动解锁。
示例:
#include <iostream>
#include <thread>
#include <mutex>
using namespace std;
mutex mtx;
int counter = 0;
void increment(int n) {
for(int i = 0; i < n; ++i) {
lock_guard<mutex> lock(mtx);
++counter;
} // 自动解锁
}
int main() {
thread t1(increment, 1000);
thread t2(increment, 1000);
t1.join();
t2.join();
cout << "Counter: " << counter << endl;
return 0;
}
lock_guard让我少写一堆清理代码,异常安全。
3.3 std::unique_lock
比lock_guard灵活,支持延迟锁定、解锁。
示例:
#include <iostream>
#include <thread>
#include <mutex>
using namespace std;
mutex mtx;
int counter = 0;
void increment(int n) {
unique_lock<mutex> lock(mtx, defer_lock);
for(int i = 0; i < n; ++i) {
lock.lock();
++counter;
lock.unlock();
}
}
int main() {
thread t1(increment, 1000);
thread t2(increment, 1000);
t1.join();
t2.join();
cout << "Counter: " << counter << endl;
return 0;
}
unique_lock适合复杂逻辑,我在服务器用它控制资源。
3.4 死锁与避免
死锁:线程A持锁1等锁2,线程B持锁2等锁1。
示例:死锁演示。
#include <iostream>
#include <thread>
#include <mutex>
using namespace std;
mutex mtx1, mtx2;
void func1() {
lock_guard<mutex> lock1(mtx1);
this_thread::sleep_for(chrono::milliseconds(10));
lock_guard<mutex> lock2(mtx2);
cout << "Func1 done" << endl;
}
void func2() {
lock_guard<mutex> lock2(mtx2);
this_thread::sleep_for(chrono::milliseconds(10));
lock_guard<mutex> lock1(mtx1);
cout << "Func2 done" << endl;
}
int main() {
thread t1(func1);
thread t2(func2);
t1.join();
t2.join();
return 0;
}
可能死锁。修复:统一加锁顺序。
用std::lock:
void func1() {
lock(mtx1, mtx2);
lock_guard<mutex> lock1(mtx1, adopt_lock);
lock_guard<mutex> lock2(mtx2, adopt_lock);
cout << "Func1 done" << endl;
}
我曾因死锁修了一夜,改用std::lock后稳定。
第四部分:条件变量

条件变量用于线程间同步,等待某个条件。
4.1 std::condition_variable
配合unique_lock,notify_one/wake_all唤醒。
示例:生产者-消费者。
#include <iostream>
#include <thread>
#include <queue>
#include <mutex>
#include <condition_variable>
using namespace std;
mutex mtx;
condition_variable cv;
queue<int> q;
bool finished = false;
void producer(int n) {
for(int i = 0; i < n; ++i) {
{
lock_guard<mutex> lock(mtx);
q.push(i);
cout << "Produced: " << i << endl;
}
cv.notify_one();
this_thread::sleep_for(chrono::milliseconds(100));
}
{
lock_guard<mutex> lock(mtx);
finished = true;
}
cv.notify_all();
}
void consumer() {
while(true) {
unique_lock<mutex> lock(mtx);
cv.wait(lock, [] { return !q.empty() || finished; });
if(q.empty() && finished) break;
if(!q.empty()) {
cout << "Consumed: " << q.front() << endl;
q.pop();
}
lock.unlock();
this_thread::sleep_for(chrono::milliseconds(200));
}
}
int main() {
thread t1(producer, 5);
thread t2(consumer);
t1.join();
t2.join();
return 0;
}
输出(顺序不定):Produced: 0 Consumed: 0 Produced: 1 Consumed: 1 ...
条件变量让我在消息队列里高效同步。
第五部分:原子操作

std::atomic提供无锁操作,性能高。
5.1 std::atomic
支持int、bool等基本类型。
示例:无锁计数器。
#include <iostream>
#include <thread>
#include <atomic>
using namespace std;
atomic<int> counter(0);
void increment(int n) {
for(int i = 0; i < n; ++i) {
counter++;
}
}
int main() {
thread t1(increment, 1000);
thread t2(increment, 1000);
t1.join();
t2.join();
cout << "Counter: " << counter << endl; // 2000
return 0;
}
原子操作比锁快,我在高并发计数用atomic。
5.2 内存序
atomic默认sequential consistency,可用memory_order_relaxed等优化。
示例:
atomic<int> x(0), y(0);
void thread1() {
x.store(1, memory_order_relaxed);
}
void thread2() {
y.store(1, memory_order_relaxed);
if(x.load(memory_order_relaxed) == 1) {
cout << "x is 1" << endl;
}
}
内存序复杂,我一般用默认,性能敏感时研究relaxed。
第六部分:异步与Future

6.1 std::async
异步运行任务,返回std::future。
示例:
#include <iostream>
#include <future>
using namespace std;
int compute(int x) {
this_thread::sleep_for(chrono::seconds(1));
return x * x;
}
int main() {
auto fut = async(launch::async, compute, 5);
cout << "Computing..." << endl;
cout << "Result: " << fut.get() << endl;
return 0;
}
输出:Computing... Result: 25
async简化异步任务,我用它跑后台计算。
6.2 std::promise
传递值给future。
示例:
#include <iostream>
#include <future>
using namespace std;
void worker(promise<int>& p) {
p.set_value(42);
}
int main() {
promise<int> p;
future<int> f = p.get_future();
thread t(worker, ref(p));
cout << "Result: " << f.get() << endl;
t.join();
return 0;
}
输出:Result: 42
promise适合线程间通信。
第七部分:C++20的jthread

C++20引入std::jthread,自动join。
示例:
#include <iostream>
#include <thread>
using namespace std;
void worker() {
cout << "jthread running" << endl;
}
int main() {
jthread t(worker); // 自动join
return 0;
}
输出:jthread running
jthread省心,我新项目都用它。
第八部分:线程池

手动管理线程麻烦,线程池复用线程。
示例:简单线程池。
#include <iostream>
#include <queue>
#include <thread>
#include <mutex>
#include <condition_variable>
#include <functional>
#include <vector>
using namespace std;
class ThreadPool {
vector<thread> workers;
queue<function<void()>> tasks;
mutex mtx;
condition_variable cv;
bool stop = false;
public:
ThreadPool(size_t n) {
for(size_t i = 0; i < n; ++i) {
workers.emplace_back([this] {
while(true) {
function<void()> task;
{
unique_lock<mutex> lock(mtx);
cv.wait(lock, [this] { return stop || !tasks.empty(); });
if(stop && tasks.empty()) return;
task = move(tasks.front());
tasks.pop();
}
task();
}
});
}
}
void enqueue(function<void()> task) {
{
lock_guard<mutex> lock(mtx);
tasks.push(move(task));
}
cv.notify_one();
}
~ThreadPool() {
{
lock_guard<mutex> lock(mtx);
stop = true;
}
cv.notify_all();
for(auto& w : workers) w.join();
}
};
int main() {
ThreadPool pool(4);
for(int i = 0; i < 8; ++i) {
pool.enqueue([i] {
cout << "Task " << i << " on thread " << this_thread::get_id() << endl;
});
}
this_thread::sleep_for(chrono::seconds(1));
return 0;
}
输出(顺序不定):Task 0 on thread ... Task 1 on thread ...
线程池是我服务器项目的标配。
第九部分:调试与优化

9.1 调试工具
- GDB:break在锁或条件变量。
- TSan:ThreadSanitizer查数据竞争,编译加-fsanitize=thread。
- Valgrind:查内存问题。
我用TSan抓到过隐藏的数据竞争。
9.2 性能优化
- 减少锁粒度:只锁关键代码。
- 无锁编程:用atomic。
- 线程亲和性:绑定线程到核(非标准,如pthread_setaffinity_np)。
- 任务划分:平衡线程负载。
我优化过实时视频处理,atomic减小锁开销,帧率提升20%。
第十部分:C++标准演进
- C++11:thread、mutex、atomic、future。
- C++17:parallel STL算法。
- C++20:jthread、semaphore、latch、barrier。
C++20的jthread让我少写一堆清理代码。
常见错误与教训
- 忘join:程序terminate。
- 数据竞争:没锁共享变量。
- 死锁:锁顺序不一致。
- 过度同步:锁太多,性能差。
- 线程爆炸:创建过多线程。
教训:多用RAII锁,测试并发场景。
结语
C++多线程编程是高性能程序的利器,但坑多。我从手动pthreads到C++20 jthread,靠多练和debug积累经验。建议新手从thread练起,老手关注同步和优化。欢迎评论你的坑!
C++多线程避坑指南


被折叠的 条评论
为什么被折叠?



