Cho một vi điều khiển đang chạy đoạn mã sau:
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
}
}
Giả sử if(has_flag)
điều kiện ước lượng là sai và chúng ta sắp thực hiện lệnh ngủ. Ngay trước khi chúng tôi thực hiện lệnh ngủ, chúng tôi nhận được một ngắt. Sau khi chúng tôi rời khỏi ngắt, chúng tôi thực hiện hướng dẫn ngủ.
Trình tự thực hiện này là không mong muốn bởi vì:
- Bộ vi điều khiển đã đi ngủ thay vì thức dậy và gọi
process()
. - Bộ vi điều khiển có thể không bao giờ thức dậy nếu sau đó không nhận được ngắt.
- Cuộc gọi đến
process()
bị hoãn cho đến khi ngắt tiếp theo.
Làm thế nào mã có thể được viết để ngăn chặn điều kiện cuộc đua này xảy ra?
Biên tập
Một số bộ vi điều khiển, chẳng hạn như tại ATMega, có bit kích hoạt chế độ Ngủ để ngăn tình trạng này xảy ra (cảm ơn bạn Kvegaoro đã chỉ ra điều này). JRoberts cung cấp một triển khai ví dụ minh họa cho hành vi này.
Các micros khác, chẳng hạn như PIC18, không có bit này và vấn đề vẫn xảy ra. Tuy nhiên, các micrô này được thiết kế sao cho các ngắt vẫn có thể đánh thức lõi bất kể liệu bit kích hoạt ngắt toàn cầu có được thiết lập hay không (cảm ơn bạn supercat vì đã chỉ ra điều này). Đối với các kiến trúc như vậy, giải pháp là vô hiệu hóa các ngắt toàn cầu ngay trước khi đi ngủ. Nếu một ngắt kích hoạt ngay trước khi thực hiện lệnh ngủ, trình xử lý ngắt sẽ không được thực thi, lõi sẽ thức dậy và một khi các ngắt toàn cầu được kích hoạt lại, trình xử lý ngắt sẽ được thực thi. Trong mã giả, việc triển khai sẽ như thế này:
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
như một int
, và tăng nó mỗi khi có gián đoạn. Sau đó thay đổi if(has_flag)
sang while (interrupts_count)
rồi ngủ. Tuy nhiên, gián đoạn có thể xảy ra sau khi bạn thoát khỏi vòng lặp while. Nếu đây là một vấn đề, sau đó làm việc xử lý trong chính nó?