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

内核2.6.24中__kfifo_put的smp_mb位置为何后置而非前置?

关于Linux内核2.6.24中__kfifo_put函数内存屏障位置的疑问

以下是内核2.6.24版本中的__kfifo_put函数代码:

unsigned int __kfifo_put(struct kfifo *fifo,
             unsigned char *buffer, unsigned int len) {

    unsigned int l;

    len = min(len, fifo->size - fifo->in + fifo->out);

    /*
     * Ensure that we sample the fifo->out index -before- we
     * start putting bytes into the kfifo.
     */

    smp_mb();

    /* first put the data starting from fifo->in to buffer end */
    l = min(len, fifo->size - (fifo->in & (fifo->size - 1)));
    memcpy(fifo->buffer + (fifo->in & (fifo->size - 1)), buffer, l);

    /* then put the rest (if any) at the beginning of the buffer */
    memcpy(fifo->buffer, buffer + l, len - l);

    /*
     * Ensure that we add the bytes to the kfifo -before-
     * we update the fifo->in index.
     */

    smp_wmb();

    fifo->in += len;

    return len;
}

我的疑问是:为何smp_mb()没有放在获取fifo->out值的操作(即len = min(len, fifo->size - fifo->in + fifo->out))之前,而是放在该操作之后?


解答

要搞懂这个问题,得先明确smp_mb()的作用和这段代码的核心诉求:

  1. 代码注释已经说得很清楚:要保证先完成对fifo->out的采样,再开始往kfifo里写数据。
  2. smp_mb()是全内存屏障,它的作用是阻止屏障前后的内存操作发生重排序——屏障之前的所有内存操作必须完全完成、对其他CPU可见后,屏障之后的内存操作才能执行。

那为什么屏障要放在读取fifo->out之后?

  • 我们要约束的是「读取fifo->out」和「后续写buffer」这两个操作的顺序:必须先拿到准确的fifo->out值(确认有足够的空闲空间),再执行写操作,绝不能让CPU把写buffer的操作重排到读取fifo->out之前。
  • 如果把smp_mb()放在读取fifo->out之前,那屏障只能保证它之前的操作(比如函数参数的读取)完成,根本管不到「读取fifo->out」和「写buffer」的顺序,完全达不到注释里的要求。
  • 放在读取fifo->out之后,就能确保:所有在屏障前的读操作(包括读取fifo->out、fifo->in)都已经完成,之后才会执行屏障后的memcpy写buffer操作,从根本上避免了生产者还没确认空闲空间就写数据、覆盖消费者未读取内容的问题。

另外结合kfifo的并发模型来看:__kfifo_put是生产者端函数,和消费者端的__kfifo_get(会修改fifo->out)并发运行。这个屏障就是为了在多CPU环境下,让生产者拿到的fifo->out是最新的、有效的值,再基于这个值安全地写入数据。

内容的提问来源于stack exchange,提问作者lan muming

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.28 16:15:20