std::call_once în C++

Rulează o funcție o singură dată, chiar dacă mai multe fire încearcă simultan.

Sintaxă
#include <mutex>
std::once_flag steag;
std::call_once(steag, functie, argumente...);

Ce face std::call_once

std::call_once(steag, f) apelează f doar prima dată pentru un anumit std::once_flag. Dacă mai multe fire ajung în același timp, unul rulează funcția, iar celelalte așteaptă până termină, apoi continuă fără s-o mai ruleze.

Este util pentru inițializări leneșe (conexiune, configurație) în cod cu mai multe fire. Dacă funcția aruncă o excepție, steagul rămâne nesetat și următorul apel încearcă din nou.

Pentru o variabilă locală static, C++11 garantează deja inițializarea o singură dată, sigur pentru fire; acolo nu ai nevoie de call_once.

Parametri

Parametru Descriere
steag Un std::once_flag care ține minte dacă funcția a rulat.
functie, argumente Funcția apelată și argumentele ei.

Ce returnează

Nimic.

Exemple

Exemplul 1: Configurația se încarcă o singură dată

Patru fire cer configurația, dar mesajul „Încarc” apare o singură dată.

#include <mutex>
#include <print>
#include <string>
#include <thread>
#include <vector>

std::once_flag configIncarcata;
std::string config;

void incarcaConfig() {
    std::println("Încarc configurația...");
    config = "limba=ro";
}

int main() {
    std::vector<std::thread> fire;
    for (int i = 0; i < 4; ++i) {
        fire.emplace_back([] { std::call_once(configIncarcata, incarcaConfig); });
    }
    for (auto& t : fire) t.join();

    std::println("Config: {}", config);
}

Rezultat

Încarc configurația...
Config: limba=ro

Greșeli frecvente

  • Folosești un bool obișnuit (if (!incarcat) { incarca(); incarcat = true; }) cu mai multe fire. Două fire pot trece de verificare în același timp și inițializarea rulează de două ori.

Comenzi înrudite

  • std::mutex: Încuietoare pentru date comune: un singur fir de execuție o poate ține la un moment dat.
  • static: Are trei sensuri: variabilă locală care își păstrează valoarea între apeluri, membru comun al clasei sau nume vizibil doar în fișierul curent.
  • std::thread: Pornește o funcție pe un fir de execuție separat, care rulează în paralel cu restul programului.