Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Thread-safety par type

L’ABI C déclare, par type, ce qui est appelable depuis quel thread (ADR-027 §B.4). En C, le compilateur ne vérifie rien : respecter ces politiques est votre responsabilité. Cette page les énonce avec les pièges concrets.

Tableau des politiques

Type / fonctionsPolitiqueCe que cela autorise
AirLog (air_log_emit, air_log_lost_count)ThreadSafemême handle partagé entre plusieurs threads
AirLog (air_log_close)consommefermeture sans usage concurrent
AirLogFields (air_log_fields_*)NON thread-safeconstruire/muter sur un seul thread
Temps & identifiants (air_instant_*, air_duration_*, air_uuid_*, air_id128_*, air_monotonic_id_next, air_status_message)réentrant / sans état partagéappel concurrent libre

AirLog = ThreadSafe

Un même handle AirLog peut être partagé entre plusieurs threads : son cœur est un Arc<JournalSink> et l’émission est un envoi de datagramme atomique. Plusieurs threads peuvent donc appeler air_log_emit / air_log_lost_count sur le même handle, en parallèle, sans verrou de votre part :

/* thread A et thread B, même `log` — OK */
air_log_emit(log, AIR_LOG_LEVEL_INFO,  "depuis A", NULL);
air_log_emit(log, AIR_LOG_LEVEL_ERROR, "depuis B", NULL);

Piège — la fermeture, elle, n’est pas concurrente. air_log_close consomme le handle (il le libère). Vous devez garantir qu’aucun autre thread n’utilise log au moment du close, et qu’il n’est appelé qu’une fois. Schéma sûr : faire travailler tous les threads, les joindre, puis close depuis un seul thread.

AirLogFields = NON thread-safe

AirLogFields est un builder mutable : chaque air_log_fields_add[_bytes] le modifie. Il n’est protégé par aucun verrou. N’y touchez jamais depuis deux threads à la fois.

Le modèle d’usage prévu — et sûr — est « construire mono-thread, puis lire » :

/* 1. Un SEUL thread construit le builder. */
AirLogFields *f = NULL;
air_log_fields_new(&f);
air_log_fields_add(f, "REQUEST_ID", "abc-123");
air_log_fields_add(f, "USER",       "alice");

/* 2. Passé en lecture (+0) à emit : sûr tant que personne ne le mute en parallèle. */
air_log_emit(log, AIR_LOG_LEVEL_INFO, "requête traitée", f);

air_log_fields_free(f);   /* libéré par le thread propriétaire */

Le danger concret. Deux threads appelant air_log_fields_add sur le même AirLogFields = course de données (corruption de la structure interne, undefined behavior). Si plusieurs threads doivent enrichir un log, donnez à chacun son propre AirLogFields, ou sérialisez les add derrière votre mutex.

Pourquoi ce choix ? Un builder est par nature un objet de travail local : le rendre thread-safe imposerait un verrou interne coûteux à tous, pour un besoin rare. La politique « un thread le construit, plusieurs peuvent ensuite logger via un AirLog partagé » couvre le cas réel sans surcoût (Principe 5 : ne pas payer pour ce qu’on n’utilise pas).

Temps & identifiants = réentrants / sans état partagé

Toutes les fonctions de temps (air_instant_now, air_instant_elapsed, air_instant_duration_since, air_duration_from_*, air_duration_as_secs_f64) et d’identifiants (air_uuid_*, air_id128_*, air_status_message) sont réentrantes
elles ne font qu’une lecture d’horloge kernel et/ou un calcul sur des POD locaux à l’appelant, sans état partagé mutable. Vous pouvez les appeler concurremment depuis autant de threads que vous voulez, chacun avec ses propres out :
/* N threads, chacun avec son AirInstant local — aucun partage, aucun verrou */
AirInstant t;
air_instant_now(&t);

air_monotonic_id_next est le seul à toucher un compteur global au processus, mais l’incrément est atomique : appel concurrent sûr, chaque thread reçoit une valeur distincte et strictement croissante. (La monotonie est garantie au sein d’un processus ; ce n’est pas un identifiant inter-processus.)

Règle mnémotechnique

  1. Logger (AirLog) : partageable entre threads pour émettre ; fermez-le seul, une fois, sans usage concurrent.
  2. Champs (AirLogFields) : un thread, un builder. Jamais de mutation concurrente.
  3. Temps & IDs : sans souci, partout, en parallèle.

English version: Thread-safety by type.