Apakah volatile diperlukan ketika variabel diakses dari> 1 ISR, tetapi tidak dibagi di luar ISR?

9

Sudah didokumentasikan dengan jelas bahwa ketika data global dibagikan dengan ISR dan program utama, data perlu dinyatakan volatileuntuk menjamin visibilitas memori (dan itu hanya cukup untuk data 1-byte; apa pun yang lebih besar memerlukan pengaturan khusus untuk menjamin juga keaslian) . Di sini kami memiliki aturan yang baik:

  • Variabel yang hanya digunakan di luar ISR tidak boleh volatil.
  • Variabel yang hanya digunakan di dalam ISR tidak boleh volatil.
  • Variabel yang digunakan baik di dalam maupun di luar ISR harus volatile.

Tetapi apakah volatilediperlukan ketika variabel diakses dari> 1 ISR, tetapi tidak dibagikan di luar ISR? Misalnya, saya memiliki fungsi yang mempertahankan keadaan internal menggunakan staticvariabel:

void func() {
    static volatile long counter; // volatile or not?
    // Do stuff with counter etc.
}

Fungsi itu disebut dalam dua cara: dari pin interrupt, dan dari perpustakaan TimerOne :

  1. attachInterrupt(0, func, CHANGE);
  2. Timer1.attachInterrupt(func);

Tidak ada masalah atomisitas, karena ketika ISR dimasukkan, interupsi secara otomatis dinonaktifkan , tetapi ini volatilelebih merupakan pertanyaan kompiler: apa yang di-cache dan apa yang tidak.

Lebih baik aman daripada menyesal, tentu saja ...

Joonas Pulakka
sumber

Jawaban:

9

volatile hanya memberi tahu pembuat kode kompiler bahwa variabel dapat dimodifikasi oleh sesuatu selain dari kode yang dihasilkan, jadi jangan menganggap salinannya tetap akurat.

Kode ISR harus ditulis / dihasilkan dengan asumsi bahwa ia tidak memiliki konteks saat masuk, dan melestarikan konteks CPU di sekitar operasi (ISR) sendiri. Jadi, seperti halnya dengan ketidakterbatasan operasi non-atom, volatilitas tergantung, dalam kasus ini * , pada apakah interupsi diizinkan untuk bersarang atau tidak. Jika non-nesting dijamin, variabel yang dibagikan tidak dapat diubah oleh selain ISR ini selama eksekusi sendiri. Jika suatu hari ISR ​​Anda mungkin digunakan di lingkungan di mana interupsi diizinkan untuk bersarang, maka kendala itu tidak lagi berlaku.

* dalam hal ini :
Saya mengasumsikan variabel yang dikelola perangkat lunak di sini. Jika kita berbicara tentang variabel yang dapat diperbarui oleh acara perangkat keras, register penghitung waktu misalnya, semua taruhan dimatikan: variabelnya tidak stabil apa pun yang terjadi.

JRobert
sumber
Jadi, selama saya tidak mengubah perilaku default Arduino "interruptts don't nest", maka variabel tidak perlu volatile, karena itu tidak dimodifikasi oleh apa pun selain kode yang dihasilkan; kompiler dapat "berasumsi" bahwa ISR dijalankan secara linear, dan itu terjadi, selama interupsi tidak bersarang. Itu masuk akal. Terima kasih!
Joonas Pulakka