编写设备驱动程序

将变量声明为可变变量

volatile 是声明任何引用设备寄存器的变量时必须应用的一个关键字。如果不使用 volatile,编译时优化程序可能会意外删除重要访问。省略使用 volatile 可能会生成很难跟踪的错误。

要防止出现难懂的错误,必须正确使用 volatilevolatile 关键字指示编译器对已声明的对象使用精确语义,特别指示不能删除或重新排序对对象的访问。设备驱动程序必须使用 volatile 限定符的两个实例为:

以下示例使用 volatile。忙标志用于防止线程在设备忙时继续执行,该标志不受锁定保护:

    while (busy) {
      /* do something else */
      }

测试线程将在另一个线程关闭 busy 标志时继续执行:

    busy = 0;

由于 busy 会在测试线程中被频繁地访问,因此编译器可能通过将 busy 的值放在寄存器中来优化测试,并测试寄存器的内容,而无需在每次测试前都读取内存中的 busy 值。测试线程将永远无法看到 busy 的更改,其他线程将只更改内存中的 busy 值,从而导致死锁。将 busy 标志声明为 volatile 会强制在每次测试前读取其值。


注 –

busy 标志的一种替代方法是使用条件变量。请参见线程同步中的条件变量


使用 volatile 限定符时,请避免意外省略的风险。例如,以下代码

    struct device_reg {
     volatile uint8_t csr;
     volatile uint8_t data;
     };
     struct device_reg *regp;

比下一个示例更可取:

    struct device_reg {
     uint8_t csr;
     uint8_t data;
     };
     volatile struct device_reg *regp;

尽管这两个示例在功能上等效,但第二个示例要求编写人员确保类型 struct device_reg 的每个声明中都使用 volatile。第一个示例将导致所有声明中都将数据视为可变数据,因此首选该示例。如上所述,如果使用 DDI 数据访问函数访问设备寄存器,就不必将变量限定为 volatile 了。