1. Mis on volatile
C keeles?
volatile
on märksõna C keeles, millega antakse kompilaatorile teada, et konkreetset muutujat tuleb käsitleda eriliselt. Tavaliselt optimeerib kompilaator koodi, et parandada programmi tõhusust, kuid volatile
käsib kompilaatoril teatud optimeerimist mitte teha. Miks sellist asja vaja on? Selleks, et käsitleda muutujaid, mille väärtus võib muutuda väliste tegurite tõttu.
Näiteks muutujad, mis saavad andmeid riistvaraandurilt või mida võivad muuta teised lõimed mitmelõimelises keskkonnas. Kui selliste muutujate puhul tehakse optimeerimist, võivad tekkida ootamatud vead või käitumine. Seepärast kasutatakse volatile
-märksõna, et öelda: “Palun loe selle muutuja väärtus iga kord otse mälust!”
Muide, kui tõlkida volatile
sõna otseses mõttes “lendab ära” või “aurustuv”, siis võib see tunduda naljakas – justkui muutuja kaoks ära. Tegelikult on aga eesmärk tagada, et iga kord loetakse korrektne ja värske väärtus.
2. volatile
eesmärgi mõistmine
volatile
märksõna eesmärk on tagada, et juhul kui muutuja väärtust võib muuta mõni väline protsess – näiteks riistvara või mõni muu süsteem – siis neid muudatusi ei jääks kompilaator märkamata. Näiteks andurid või riistvararegistrid võivad uuendada oma väärtusi igal kordusetsüklil.
Tavaliselt võib kompilaator optimeerimise käigus eeldada, et tsükli sees muutumatu muutuja väärtust võib vahemällu salvestada. Kuid kui kasutatakse volatile
, siis kästakse kompilaatoril lugeda muutuja väärtust iga kord otse mälust.
volatile int sensor_value;
while (1) {
// Tagab, et anduri väärtus loetakse iga kord õigesti
printf("Sensor value: %dn", sensor_value);
}
Selles näites võib ilma volatile
-ta juhtuda, et kompilaator salvestab sensor_value vahemällu ja prindib iga kord sama väärtuse. volatile
märkimisega tagatakse, et iga kord loetakse anduri kõige värskem väärtus.
3. volatile
roll manussüsteemides
volatile
mängib eriti olulist rolli manussüsteemides. Manussüsteemides jälgitakse sageli otse riistvara olekut või suheldakse andurite ja täiturseadmetega, mistõttu on hädavajalik käsitleda muutujaid, mille väärtused muutuvad reaalajas, õigesti ja täpselt.
Näiteks muutujad, mida kasutatakse riistvararegistrites või katkestusteenuse rutiinides (ISR – Interrupt Service Routines), muudetakse sageli väljaspool programmi tavapärast juhtvoogu. Kui selliseid muutujaid ei märgita volatile
-ga, võib kompilaator neid vahemällu salvestada ja ei pruugi peegeldada riistvara tegelikku hetkeseisu.
volatile int interrupt_flag;
void interrupt_handler() {
interrupt_flag = 1; // Seab lipu katkestuse tekkimisel
}
int main() {
while (!interrupt_flag) {
// Ootab, kuni lipp on seatud
}
printf("Interrupt occurred!n");
return 0;
}

4. volatile
kasutamine mitmelõimelises keskkonnas
Ka mitmelõimelistes programmides võib volatile
olla kasulik. Siiski tuleb tähele panna, et volatile
ei taga lõimedevahelist sünkroniseerimist. See märksõna lihtsalt takistab muutuja väärtuse vahemällu salvestamist, kuid ei taga lõimede turvalist (thread-safe) käitumist ega atomaarseid operatsioone.
volatile
sobib näiteks jagatud lippude (flag) muutujate puhul, mida lõimed omavahel jagavad. Keerulisemateks sünkroniseerimisvajadusteks tuleb siiski kasutada muid mehhanisme, nagu mutexid või semaforid.
volatile int shared_flag = 0;
void thread1() {
// Lõim 1 muudab lippu
shared_flag = 1;
}
void thread2() {
// Lõim 2 jälgib lipu muutust
while (!shared_flag) {
// Ootab, kuni lipp on seatud
}
printf("Flag detected!n");
}
5. Levinud valearusaamad volatile
kohta
volatile
kasutamise kohta leidub palju valearusaamu. Üks levinumaid on usk, et volatile
abil saab lõimedevahelist sünkroniseerimist saavutada. Tegelikult volatile
ei taga sünkroniseerimist ega välista samaaegset juurdepääsu – see ei paku mutual exclusion (vastastikust välistamist).
Samuti on oluline mõista, et volatile
ei peata kõiki kompilaatori optimeerimisi. Näiteks inkrement- ja dekrementoperatsioonid volatile
muutujatel ei ole atomaarse iseloomuga. See tähendab, et mitmelõimelises keskkonnas võivad sellised operatsioonid põhjustada ootamatut käitumist või võistlusseisundeid (race conditions).
volatile int counter = 0;
void increment_counter() {
counter++; // See operatsioon ei ole atomaarne!
}
6. Parimad praktikad volatile
kasutamiseks
Siin on mõned parimad tavad volatile
märksõna õige kasutamise jaoks:
- Kasutada alati riistvaraga suhtlemisel: Kui tegemist on riistvararegistrite või väliste sisenditega seotud muutujatega, kasuta
volatile
-märksõna, et tagada alati värske väärtuse lugemine. - Ära kasuta lõimedevaheliseks sünkroniseerimiseks:
volatile
ei ole mõeldud lõimedevaheliseks sünkroniseerimiseks. Keerulisemates olukordades kasuta mutex’e või semafoore. - Väldi väärkasutust: Kui
volatile
kasutatakse ilma tegeliku vajaduseta, võib see põhjustada jõudluse langust või ootamatut käitumist. Kasuta seda ainult siis, kui see on tõesti vajalik.
7. volatile
nutikas kasutamine tõhusa koodi jaoks
volatile
mängib olulist rolli programmeerimisel, eriti riistvaraga suhtlemisel ja mitmelõimelistes keskkondades. Siiski on vajalik selle märksõna õige mõistmine ja läbimõeldud kasutamine.
Kui volatile
kasutatakse õigesti, võib see suurendada programmi töökindlust ja stabiilsust. Kuid sama oluline on ka aru saada selle piirangutest ja mitte eeldada, et see lahendab kõik sünkroniseerimise või turvalisuse probleemid automaatselt.