Aşağıdaki kodu çalıştıran bir mikro denetleyici verildi:
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
}
}
Durumun yanlış olarakif(has_flag)
değerlendirildiğini ve uyku talimatını uygulamak üzere olduğumuzu varsayalım . Uyku talimatını uygulamadan hemen önce bir kesinti alırız. Kesmeden ayrıldıktan sonra uyku talimatını uygularız.
Bu yürütme sırası istenmez, çünkü:
- Mikrodenetleyici uyanmak ve çağırmak yerine uykuya daldı
process()
. - Bundan sonra herhangi bir kesinti alınmazsa mikrodenetleyici asla uyanamayabilir.
- İçin yapılan çağrı
process()
, bir sonraki kesintiye kadar ertelenir.
Bu yarış koşulunun oluşmasını önlemek için kod nasıl yazılabilir?
Düzenle
ATMega gibi bazı mikrodenetleyiciler, bu durumun ortaya çıkmasını önleyen bir Uyku etkin bitine sahiptir (bunu işaret ettiğiniz için Kvegaoro'ya teşekkür ederiz). JRoberts bu davranışı örnekleyen bir örnek uygulama sunmaktadır.
PIC18'lerde olduğu gibi diğer mikrolarda bu bit yoktur ve sorun hala devam eder. Bununla birlikte, bu mikrolar, küresel kesme etkinleştirme bitinin ayarlanıp ayarlanmadığına bakılmaksızın kesmelerin yine de çekirdeği uyandıracak şekilde tasarlanmıştır (bunu işaret ettiğiniz için teşekkür ederim supercat). Bu tür mimariler için çözüm, uyumadan hemen önce küresel kesintileri devre dışı bırakmaktır. Bir kesme uyku talimatını uygulamadan hemen önce tetiklenirse, kesme işleyicisi yürütülmez, çekirdek uyanır ve genel kesmeler yeniden etkinleştirildikten sonra kesme işleyicisi yürütülür. Sahte kodda, uygulama şöyle görünecektir:
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
olarak yapacağım int
ve her kesinti olduğunda bunu arttıracağım. Sonra değiştirmek if(has_flag)
için while (interrupts_count)
ve daha sonra uyku. Bununla birlikte, while döngüsünden çıktıktan sonra kesme meydana gelebilir. Bu bir sorunsa, kesmenin kendisindeki işlem mi yapılır?