5

以下は、Barrelfish オペレーティング システムの実行中に Pandaboard の LED を点滅させるコードです。gpio_oe私の質問は、およびの定義から 'volatile' キーワードが削除された場合、なぜ LED が点滅しないのかということですgpio_dataout

static volatile uint32_t *gpio_oe = (uint32_t *)(GPIO_BASE + 0x0134);
static volatile uint32_t *gpio_dataout = (uint32_t *)(GPIO_BASE + 0x013C);

void led_flash
{
    // Enable output
    *gpio_oe &= (~(1 << 8));

    // Toggle LED on and off till eternity
    while(true)
    {
      *gpio_dataout ^= (1 << 8);  // Set means LED on; Clear means LED off
       time_delay();  // To give blinking effect
    }
}

変数の値がプログラムの外部のソースを介して自発的に変化する可能性がある場合は、volatile を使用する必要があることを知っています。しかし、ここではそのようなケースは見られません。LED を点滅させるための while ループ全体を無意味にする、コンパイラーが実行する最適化は何ですか? そして、そのような最適化の背後にあるロジックは何ですか。そのような最適化が理にかなっている正当なケースはありますか?

4

4 に答える 4

9

volatileまた、メモリへの書き込みと、生成されたコードがvolatile変数にアクセスする順序を強制する必要があります。通常の変数を使用すると、コンパイラは書き込みが不要であると判断し、それらを破棄するか、最後のものだけを保持する場合があります。

コメントから移動:変数の読み取りが見られない場合、コンパイラは何も書き込まない可能性があり、変数を削除することさえあります。

于 2013-02-05T14:56:28.597 に答える
5

コンパイラが判断できる限り、値*gpio_oe*gpio_dataout書き込まれますが、読み取られることはありません。通常のデータ メモリの場合、このようなアクセス パターンは完全に冗長であるため、最適化することができます。読み取られるが書き込まれない場所についても同様です。

ただし、メモリ マップド I/Oの場合、「メモリ」ロケーションへのアクセスには、コンパイラが認識していない副作用があります。場所を宣言するvolatileと、コードで記述されているとおりに場所に明示的にアクセスする必要があることがコンパイラに通知されます。

メモリ マップド I/O と同様に、別のスレッド (RTOS タスクや割り込みハンドラなど) 間で共有されるメモリでも同様の問題が発生します。これは、言語がこれらのコンテキストを同様に認識しないためです。

Embedded.com では、この件について多くの記事で取り上げています。

于 2013-02-05T20:04:20.370 に答える
4

ハードウェアレジスタに直接アクセスしようとしているので、すべてのアクセスがメモリバスに行き、通常の変数のようにレジスタに留まらないようにします。Volatileは、その変数のすべての使用を強制的にメモリバスに送信またはメモリバスから送信するようにコンパイラに指示します。データキャッシュの問題はまだありますが、それは別のトピックです。

編集:

無限ループでは、コンパイラがその変数をレジスタに最適化して、メモリバスに移動しないことを意味し、gpioを変更しないことを意味し、LEDが点滅しないことを意味します。これは、揮発性を削除し、コンパイルしてから逆アセンブルするかどうかを簡単に確認できるはずです(または、asmにコンパイルすると、バイナリを逆アセンブルする方がはるかに読みやすくなります)。

于 2013-02-05T15:36:30.837 に答える
1

volatileコンパイラーが変数への読み取りと書き込みを最適化するのを防ぎます。それがないと、コンパイラーは値が変更されないと想定し、フラグが読み取られるループを 1 回の呼び出しで置き換えるか、変数が後で使用されない場合は書き込みを削除する可能性があります。この質問を参照してください。

Cで揮発性が必要なのはなぜですか?

于 2013-02-05T14:56:07.757 に答える