次のコードを実行しているマイクロコントローラーがあるとします。
volatile bool has_flag = false;
void interrupt(void) //called when an interrupt is received
{
    clear_interrupt_flag(); //clear interrupt flag
    has_flag = true; //signal that we have an interrupt to process
}
int main()
{
    while(1)
    {
        if(has_flag) //if we had an interrupt
        {
            has_flag = false; //clear the interrupt flag
            process(); //process the interrupt
        }
        else
            sleep(); //place the micro to sleep
    }
}
if(has_flag)条件がfalseと評価され、sleep命令を実行しようとしているとします。  右我々はスリープ命令を実行する前に、我々は、割り込みを受けます。割り込みを離れた後、sleep命令を実行します。  
次の理由により、この実行シーケンスは望ましくありません。
- マイクロコントローラーは、目を覚まして呼び出すのではなく、スリープ状態になりましたprocess()。
- その後に割り込みが受信されない場合、マイクロコントローラが起動しないことがあります。
- への呼び出しprocess()は、次の割り込みまで延期されます。
この競合状態の発生を防ぐために、コードをどのように記述できますか?
編集
ATMegaなどの一部のマイクロコントローラーには、この状態の発生を防ぐスリープイネーブルビットがあります(指摘してくれたKvegaoroに感謝)。JRobertsは、この動作を例示する実装例を提供しています。
PIC18のような他のマイクロにはこのビットがなく、問題はまだ発生します。ただし、これらのマイクロは、グローバル割り込み有効化ビットが設定されているかどうかに関係なく、割り込みがコアをウェイクアップできるように設計されています(これを指摘してくれてありがとう)。このようなアーキテクチャの場合、解決策は、スリープ状態になる直前にグローバル割り込みを無効にすることです。スリープ命令を実行する直前に割り込みが発生した場合、割り込みハンドラーは実行されず、コアがウェイクアップし、グローバル割り込みが再度有効になると、割り込みハンドラーが実行されます。疑似コードでは、実装は次のようになります。
int main()
{
    while(1)
    {
        //clear global interrupt enable bit.
        //if the flag tested below is not set, then we enter
        //sleep with the global interrupt bit cleared, which is
        //the intended behavior.
        disable_global_interrupts();
        if(has_flag) //if we had an interrupt
        {
            has_flag = false; //clear the interrupt flag
            enable_global_interrupts();  //set global interrupt enable bit.
            process(); //process the interrupt
        }
        else
            sleep(); //place the micro to sleep
    }
}
interrupt_flag、int割り込みがあるたびにインクリメントします。次にをに変更しif(has_flag)てwhile (interrupts_count)から、スリープします。それにもかかわらず、whileループを終了した後に割り込みが発生する可能性があります。これが問題である場合、割り込み自体で処理を行いますか?