You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何pthread自旋锁比互斥锁快很多?如何兼顾性能与避免自旋锁?

单生产者单消费者队列的同步性能疑问

我以一个生产者消费者示例为参考,开发了适用于单生产者、单消费者场景的多线程FIFO队列,队列仅在这两个线程间共享。测试中发现同步机制的开销差异极大:使用mutex时,完成1000万条数据的添加与移除操作耗时约3秒,而使用spinlock仅需1.5秒。

我实现的阻塞式添加函数如下(阻塞式移除函数逻辑类似),此前John Bollinger指出原自旋锁代码在多读写场景下存在竞态问题,我已对函数进行了更新:

static void
spin_while_full(volatile synced_queue *me) {
    while (me->queue->n_elements == me->queue->capacity) {
    }
}

void
synced_queue_add(synced_queue *me, void *value) {
    synced_queue_lock_type tp = me->lock_type;
    if (tp == SYNCED_QUEUE_SPIN_LOCK) {
        while (true) {
            pthread_spin_lock(&me->lock);
            if (me->queue->n_elements < me->queue->capacity) {
                break;
            }
            pthread_spin_unlock(&me->lock);
        }
    } else if (tp == SYNCED_QUEUE_SPIN_LOCK_UNCONTESTED) {
        spin_while_full(me);
        pthread_spin_lock(&me->lock);
    } else if (tp == SYNCED_QUEUE_MUTEX) {
        pthread_mutex_lock(&me->mutex);
        while (me->queue->n_elements == me->queue->capacity) {
            pthread_cond_wait(&me->var_prod, &me->mutex);
        }
    } else {
        assert(false);
    }
    queue_add(me->queue, value);
    if (tp == SYNCED_QUEUE_SPIN_LOCK ||
        tp == SYNCED_QUEUE_SPIN_LOCK_UNCONTESTED) {
        pthread_spin_unlock(&me->lock);
    } else {
        pthread_mutex_unlock(&me->mutex);
        pthread_cond_signal(&me->var_cons);
    }
}

库使用者可通过lock_type指定同步方式,三种锁的基准测试结果如下:

=== benchmark_synced_queue
spinlock               1024 elements  0.17 us/job
uncontested spinlock   1024 elements  0.14 us/job
mutex                  1024 elements  0.31 us/job
spinlock                512 elements  0.17 us/job
uncontested spinlock    512 elements  0.14 us/job
mutex                   512 elements  0.31 us/job
spinlock                256 elements  0.15 us/job
uncontested spinlock    256 elements  0.14 us/job
mutex                   256 elements  0.28 us/job
spinlock                128 elements  0.15 us/job
uncontested spinlock    128 elements  0.14 us/job
mutex                   128 elements  0.29 us/job
spinlock                 64 elements  0.16 us/job
uncontested spinlock     64 elements  0.14 us/job
mutex                    64 elements  0.28 us/job
spinlock                 32 elements  0.18 us/job
uncontested spinlock     32 elements  0.15 us/job
mutex                    32 elements  0.15 us/job
spinlock                 16 elements  0.21 us/job
uncontested spinlock     16 elements  0.16 us/job
mutex                    16 elements  0.30 us/job
spinlock                  8 elements  0.29 us/job
uncontested spinlock      8 elements  0.16 us/job
mutex                     8 elements  0.60 us/job
spinlock                  4 elements  0.43 us/job
uncontested spinlock     4 elements  0.17 us/job
mutex                     4 elements  1.21 us/job

从结果可见,“正确实现”的自旋锁虽比存在竞态问题的自旋锁略慢,但自旋锁与mutex的性能差距更为显著。

pthread手册强烈不建议使用自旋锁:

自旋锁应结合实时调度策略(SCHED_FIFO或SCHED_RR)使用。在SCHED_OTHER等非确定性调度策略下使用自旋锁可能表明设计存在问题。……用户态自旋锁并非通用锁解决方案,本质上易出现优先级反转和无界自旋时间。使用自旋锁的程序员不仅要在代码上格外谨慎,还要注意系统配置、线程放置和优先级分配。

我的疑问是:为何mutex的锁定操作比spinlock慢这么多?自旋锁的问题在于会持续占用大量CPU资源,有没有办法不用自旋锁仍能获得相近的良好性能?

内容的提问来源于stack exchange,提问作者Changed My Name Again

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.12 09:28:09