并发编程最难的部分往往不是 API,而是建立对共享状态的直觉。本文从一个简单的生产者消费者模型开始,记录我对线程同步的理解。
从任务开始,而不是从线程开始
先描述任务之间的关系,再决定是否需要线程。一个好的并发设计应该让数据的所有权和生命周期清晰可见。
std::mutex mutex;
std::condition_variable ready;
std::queue<Job> jobs;
void worker() {
while (running) {
std::unique_lock lock(mutex);
ready.wait(lock, [] { return !jobs.empty() || !running; });
if (!running && jobs.empty()) return;
auto job = std::move(jobs.front());
jobs.pop();
lock.unlock();
process(job);
}
}
Mutex 保护的边界
锁应该保护不变量,而不是包裹所有代码。把耗时工作移出临界区,通常比盲目增加线程更有效。
小结
并发代码值得慢慢写、反复测。先用明确的模型解决问题,再用工具验证性能。