ProgrammatieSysteem/backend en Embedded-ontwikkelaar

Vertel over de regels voor het werken met globale variabelen (static) in Rust. Hoe wordt veiligheid gegarandeerd bij gelijktijdige toegang en wat zijn de verschillen tussen de verschillende manieren van initialisatie en synchronisatie?

Slaag voor sollicitatiegesprekken met de Hintsage AI-assistent

Antwoord

In Rust worden globale variabelen gedeclareerd met het sleutelwoord static. Dergelijke variabelen leven gedurende de hele uitvoering van het programma. Standaard is de toegang tot onveranderlijke static veilig, maar voor veranderlijke is het nodig om unsafe te gebruiken, omdat de compiler niet kan garanderen dat er geen race conditions zijn.

Voor veilige toegang tot veranderlijke globale variabelen worden speciale wrapper-types gebruikt: Mutex, RwLock, Atomic* types of externe crates (lazy_static, once_cell). Initialisatie is "luiaardig" als het uitstellen van het creëren van een object bij de eerste toegang vereist is.

Voorbeelden:

static COUNTER: AtomicUsize = AtomicUsize::new(0); static ref CONFIG: Config = read_config(); // met lazy_static of once_cell

Misleidende vraag

Kan je een veranderlijke globale variabele zonder speciale types declareren, als deze alleen uit één thread gebruikt gaat worden? Moet je unsafe schrijven?

Antwoord: De compiler zal vereisen om unsafe te gebruiken bij elke wijziging van een globale variabele, zelfs als de logica single-threaded is. Dit is een algemene vereiste voor alle static mut. Alleen als de variabele is verpakt in een synchroniserende structuur (Mutex, atomisch, etc.), zal de compiler veilige toegang toestaan.

static mut VALUE: i32 = 0; unsafe { VALUE += 1; }

Voorbeelden van echte fouten door onwetendheid over de nuances van het onderwerp


Verhaal

In een webservice werd bij de initialisatie van de globale cache een gewone static-variabele met een string gebruikt. Meerdere threads schreven er gelijktijdig naar, er ontstonden "bitten" in het geheugen en de applicatie viel om door race conditions.


Verhaal

In een command-line tool in Rust werd een statische variabele zonder synchronisatie gewijzigd, omdat het "alleen via main werkt". Later werd de code aangepast voor multithreading, waarbij global mutable state werd vergeten, wat leidde tot moeilijk te traceren bugs.


Verhaal

In een embedded-programma werd de static CONFIG verkeerd geïnitialiseerd via een functie bij opstart, maar werd niet gegarandeerd dat deze precies één keer zou worden aangeroepen. Als gevolg daarvan kreeg een deel van de code toegang tot de niet-geïnitialiseerde configuratie (null reference).