ProgrammationDéveloppeur système/backend et embarqué

Parlez des règles de travail avec des variables globales (static) en Rust. Comment la sécurité est-elle assurée lors de l'accès simultané et quelles sont les différences entre les différentes manières d'initialiser et de synchroniser ?

Réussissez les entretiens avec l'assistant IA Hintsage

Réponse

En Rust, les variables globales sont déclarées avec le mot clé static. Ces variables vivent pendant toute l'exécution du programme. Par défaut, l'accès aux static immuables est sûr, mais l'accès aux static mutables nécessite d'utiliser unsafe, car le compilateur ne peut garantir l'absence de conditions de course.

Pour un accès sûr aux variables globales mutables, on utilise des types d'emballage spéciaux : Mutex, RwLock, types Atomic* ou des crates externes (lazy_static, once_cell). L'initialisation est « paresseuse » si la création de l'objet est retardée jusqu'à la première demande.

Exemples :

static COUNTER: AtomicUsize = AtomicUsize::new(0); static ref CONFIG: Config = read_config(); // à l'aide de lazy_static ou once_cell

Question piège

Peut-on déclarer une variable globale mutable sans types spéciaux, si elle n'est utilisée que par un seul thread ? Faut-il écrire unsafe ?

Réponse : Le compilateur exigera d'utiliser unsafe pour toute modification d'une variable globale, même si la logique est unipolaire. C'est une exigence générale pour tous les static mut. Ce n'est que si la variable est encapsulée dans une structure de synchronisation (Mutex, atomique, etc.), que le compilateur permettra un accès sécurisé.

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

Exemples d'erreurs réelles dues à l'ignorance des subtilités du sujet


Histoire

Dans un service web, lors de l'initialisation d'un cache global, on a utilisé une simple variable static contenant une chaîne. Plusieurs threads écrivaient en même temps dedans, provoquant des « bits » de mémoire et des plantages d'application à cause des conditions de course.


Histoire

Dans un utilitaire d'équipe en Rust, on modifiait une variable statique sans synchronisation, parce que « ça fonctionne uniquement via main ». Plus tard, le code a été adapté pour le multithreading, en oubliant l'état mutable global, ce qui a provoqué de très difficiles bogues.


Histoire

Dans un programme embarqué, on a mal initialisé le static CONFIG via une fonction au démarrage, mais on n'a pas garanti qu'elle serait appelée exactement une fois. En conséquence, certaines parties du code accédaient à une configuration non initialisée (référence nulle).