并发编程

基础

  1. 深入理解 Linux C/C++ 编程:
    • 熟练掌握 C/C++: 这是系统编程的基础,特别是指针、内存管理、数据结构。
    • 掌握标准 I/O、文件操作、进程控制 (fork, exec, wait): 理解进程的创建、执行和生命周期。
    • 学习信号 (Signals): 理解异步事件处理机制,虽然在现代并发编程中不常用作主要同步手段,但理解其原理很重要。
    • 掌握基本的系统调用和库函数。
  2. 理解计算机体系结构与操作系统原理:
    • CPU 架构 (x86-64, ARM): 了解寄存器、缓存 (Cache, L1/L2/L3)、内存层次结构、总线。
    • 操作系统核心概念: 进程 (Process) vs. 线程 (Thread)、调度 (Scheduling)、虚拟内存、上下文切换 (Context Switching) 的开销。
    • 理解并发 (Concurrency) vs. 并行 (Parallelism): 并发是关于结构(同时处理多个任务),并行是关于执行(同时运行多个任务)。

核心并发机制 - 线程与同步

这是最核心的部分,主要使用 POSIX 线程 (Pthreads)。

  1. POSIX 线程 (Pthreads) API:

    • 线程创建与管理: pthread_create, pthread_join, pthread_detach, pthread_exit
    • 线程属性: pthread_attr_t (栈大小、调度策略等)。
    • 线程特定数据 (TSD): pthread_key_create, pthread_setspecific, pthread_getspecific
  2. 同步原语 (Synchronization Primitives):

    • 互斥锁 (Mutex): pthread_mutex_t, pthread_mutex_lock, pthread_mutex_unlock。理解死锁、活锁、优先级反转。
    • 条件变量 (Condition Variables): pthread_cond_t, pthread_cond_wait, pthread_cond_signal, pthread_cond_broadcast。掌握“等待 - 通知”模式,与互斥锁配合使用。
    • 读写锁 (Read-Write Locks): pthread_rwlock_t。适用于读多写少的场景。
    • 自旋锁 (Spinlocks): pthread_spinlock_t。在锁竞争不激烈且临界区很短时可能更高效(避免上下文切换开销),但会浪费 CPU 周期。
    • 屏障 (Barriers): pthread_barrier_t。用于同步一组线程在某个点汇合。
  3. 实践与挑战:

    • 经典问题: 实现生产者 - 消费者问题、读者 - 写者问题、哲学家就餐问题。深刻理解同步的必要性。
    • 调试: 学习使用 gdb 调试多线程程序,理解线程堆栈。
    • 工具: 使用 valgrind (特别是 helgrinddrd) 检测数据竞争、死锁等并发错误。
    • 性能分析: 使用 perf 工具分析程序性能,关注上下文切换、缓存未命中等。

高级主题与现代 C++

  1. 避免低级错误:

    • 数据竞争 (Data Race): 多个线程未同步地访问同一内存位置,至少一个是写操作。
    • 死锁 (Deadlock): 多个线程相互等待对方持有的锁。
    • 活锁 (Livelock): 线程持续改变状态但无法取得进展。
    • 优先级反转 (Priority Inversion): 低优先级线程持有高优先级线程需要的锁。
    • 虚假唤醒 (Spurious Wakeup): 条件变量 wait 可能在没有 signal/broadcast 的情况下返回。
  2. 现代 C++ 并发 (C++11 及以后):

    • <thread>: std::thread,更现代、类型安全的线程接口。
    • <mutex>: std::mutex, std::lock_guard, std::unique_lock, std::shared_mutex (C++17)。
    • <condition_variable>: std::condition_variable
    • <atomic>: std::atomic<T>。提供无锁 (lock-free) 编程的基础,理解内存序 (memory order - memory_order_relaxed, memory_order_acquire, memory_order_release, memory_order_acq_rel, memory_order_seq_cst) 至关重要。
    • <future><promise>: std::async, std::future, std::promise。用于异步任务和结果获取。
    • <shared_mutex> (C++17): 提供共享/独占锁语义。
  3. 无锁编程 (Lock-Free Programming):

    • 基于原子操作和内存序构建高性能数据结构(如无锁队列、栈)。
    • 极其复杂且容易出错,通常只在性能要求极高且经过严格测试的场景下使用。优先考虑使用成熟的库。

性能优化与调试

  1. 性能分析 (Profiling):
    • perf (Linux): 系统级性能分析神器。分析 CPU 周期、缓存命中/未命中、分支预测、上下文切换、锁争用 (perf lock)。
    • gprof / gperftools (Google Performance Tools): 分析函数调用时间和开销。
    • htop / top: 监控 CPU、内存、线程使用情况。
    • strace / ltrace: 跟踪系统调用和库调用。
  2. 优化策略:
    • 减少锁争用: 缩小临界区、使用细粒度锁、无锁数据结构、避免在锁内进行耗时操作(如 I/O)。
    • 减少上下文切换: 合理设置线程数(通常接近 CPU 核心数),避免创建过多线程。
    • 提高缓存局部性: 数据访问模式尽量局部化,减少缓存未命中。
    • 负载均衡: 确保工作在线程间均匀分配。
  3. 调试工具:
    • gdb: 多线程调试 (thread, info threads, thread apply all bt)。
    • valgrind (helgrind, drd): 检测数据竞争、死锁。
    • AddressSanitizer (ASan) + ThreadSanitizer (TSan): Google 的 sanitizer 工具,强烈推荐!TSan 能非常有效地检测数据竞争和死锁,集成到编译器中,性能开销相对可接受。