1. Linux线程同步与互斥的本质问题
当多个线程并发访问共享资源时,会出现数据竞争(Data Race)问题。我在调试一个多线程日志系统时,曾遇到过计数器值莫名跳变的诡异现象——这就是典型的线程安全问题。通过gdb反汇编发现,简单的counter++操作在底层实际包含三条指令:读取、修改、写入。当线程A执行到修改阶段时,线程B可能已经完成了写入,导致最终结果不符合预期。
关键教训:在x86架构下,即使像
i++这样的简单操作也不是原子性的。必须通过同步机制保证操作的完整性。
现代处理器为了提升性能采用的指令重排(Instruction Reordering)更会加剧这个问题。我曾用如下代码测试:
c复制// 线程A
value = 42;
ready = 1;
// 线程B
while(!ready);
printf("%d\n", value);
理论上应该永远输出42,但在ARM架构的嵌入式设备上,确实观测到过输出0的情况。这是因为编译器和CPU可能对无关指令进行重排序。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 互斥锁的深度实践
2.1 pthread_mutex的进阶用法
标准互斥锁pthread_mutex_t有几种变形值得关注:
c复制// 错误检查锁:可检测同一线程重复加锁
pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ERRORCHECK);
// 递归锁:允许同一线程多次加锁
pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
// 自适应锁:应对高竞争场景
pthread_mutexattr_setprotocol(&attr, PTHREAD_PRIO_INHERIT);
在实现线程安全的哈希表时,我对比过不同锁的性能:当并发度超过16线程时,自适应锁的吞吐量比普通锁高出37%。
2.2 锁粒度优化策略
过粗的锁会导致性能瓶颈,过细又可能引发死锁。我的经验法则是:
- 对写多读少的场景,采用细粒度锁(如每个哈希桶独立加锁)
- 对读多写少的场景,考虑读写锁(
pthread_rwlock_t) - 对计数器等简单场景,直接使用原子操作(`__atomic_add_fet
