Build a value exactly once and report how many later reads were served from cache.

run-once initialization A write-once value is built by the first reader and shared by the rest. A `std::once_flag` paired with `std::call_once` runs its initializer the first time it is reached and skips it on every later call, so the build counter rises to one no matter how many reads occur. Each read is served whether or not it triggered the build, so the report compares served reads against builds and labels the value unset when never read, set when built on its only read, or cached when later reads reused the single build.

Call Once Coordination Report

reads
call_once_coordination_report.cpp
Replay: real traced execution (multi-file project)
#include <iostream>
#include <mutex>
#include <string>

int main() {
    int reads = 1;
    std::once_flag built;
    int value = 0;
    int builds = 0;
    int served = 0;

    for (int i = 0; i < reads; ++i) {
        std::call_once(built, [&]() {
            value = 42;
            builds += 1;
        });
        served += 1;
    }

    int cached = (builds > 0) ? value : 0;

    std::string status;
    if (served == 0) {
        status = "unset";
    } else if (served > builds) {
        status = "cached";
    } else {
        status = "set";
    }

    std::cout << "reads=" << reads
              << " served=" << served
              << " builds=" << builds
              << " value=" << cached
              << " " << status << std::endl;
    return 0;
}
#include <iostream>
#include <mutex>
#include <string>

int main() {
    int reads = 0;
    std::once_flag built;
    int value = 0;
    int builds = 0;
    int served = 0;

    for (int i = 0; i < reads; ++i) {
        std::call_once(built, [&]() {
            value = 42;
            builds += 1;
        });
        served += 1;
    }

    int cached = (builds > 0) ? value : 0;

    std::string status;
    if (served == 0) {
        status = "unset";
    } else if (served > builds) {
        status = "cached";
    } else {
        status = "set";
    }

    std::cout << "reads=" << reads
              << " served=" << served
              << " builds=" << builds
              << " value=" << cached
              << " " << status << std::endl;
    return 0;
}
#include <iostream>
#include <mutex>
#include <string>

int main() {
    int reads = 2;
    std::once_flag built;
    int value = 0;
    int builds = 0;
    int served = 0;

    for (int i = 0; i < reads; ++i) {
        std::call_once(built, [&]() {
            value = 42;
            builds += 1;
        });
        served += 1;
    }

    int cached = (builds > 0) ? value : 0;

    std::string status;
    if (served == 0) {
        status = "unset";
    } else if (served > builds) {
        status = "cached";
    } else {
        status = "set";
    }

    std::cout << "reads=" << reads
              << " served=" << served
              << " builds=" << builds
              << " value=" << cached
              << " " << status << std::endl;
    return 0;
}
  1. reads ← 1, built ← (empty), value ← 0, builds ← 0, served ← 0

    5int main() {6    int reads→ 1 = 1; //@reads=0, 27    std::once_flag built→ (empty);8    int value→ 0 = 0;9    int builds→ 0 = 0;10    int served→ 0 = 0;
  2. served ← 1

    12for (int i0 = 0; i < reads1; ++i) {13    std::call_once(built(empty), [&]() {14        value = 42;15        builds += 1;16    });17    served→ 1 += 1;18}
  3. cached ← 42, status ← (empty)

    20int cached→ 42 = (builds1 > 0) ? value42 : 0;2122std::string status→ (empty);23if (served == 0) {
  4. status ← set

    26    status = "cached";27} else {28    status→ set = "set";29}
  5. std::cout << "reads=" << reads

    31    std::cout << "reads=" << reads132              << " served=" << served133              << " builds=" << builds134              << " value=" << cached4235              << " " << statusset << std::endl;36    return 0;37}
    outputreads=1 served=1 builds=1 value=42 set
  1. reads ← 0, built ← (empty), value ← 0, builds ← 0, served ← 0

    5int main() {6    int reads→ 0 = 0;7    std::once_flag built→ (empty);8    int value→ 0 = 0;9    int builds→ 0 = 0;10    int served→ 0 = 0;1112    for (int i = 0; i < reads; ++i) {13        std::call_once(built, [&]() {14            value = 42;15            builds += 1;16        });17        served += 1;18    }1920    int cached→ 0 = (builds0 > 0) ? value0 : 0;2122    std::string status→ (empty);23    if (served == 0) {
  2. status ← unset

    22std::string status;23if (served0 == 0) {24    status→ unset = "unset";25} else if (served > builds) {
  3. std::cout << "reads=" << reads

    31    std::cout << "reads=" << reads032              << " served=" << served033              << " builds=" << builds034              << " value=" << cached035              << " " << statusunset << std::endl;36    return 0;37}
    outputreads=0 served=0 builds=0 value=0 unset
  1. reads ← 2, built ← (empty), value ← 0, builds ← 0, served ← 0

    5int main() {6    int reads→ 2 = 2;7    std::once_flag built→ (empty);8    int value→ 0 = 0;9    int builds→ 0 = 0;10    int served→ 0 = 0;
  2. served ← 1

    pass 1 of 2
    12for (int i0 = 0; i < reads2; ++i) {13    std::call_once(built(empty), [&]() {14        value = 42;15        builds += 1;16    });17    served→ 1 += 1;18}
  3. served ← 2

    pass 2 of 2
    12for (int i1 = 0; i < reads2; ++i) {13    std::call_once(built(empty), [&]() {14        value = 42;15        builds += 1;16    });17    served→ 2 += 1;18}
  4. cached ← 42, status ← (empty)

    20int cached→ 42 = (builds1 > 0) ? value42 : 0;2122std::string status→ (empty);23if (served == 0) {
  5. status ← cached

    24    status = "unset";25} else if (served2 > builds1) {26    status→ cached = "cached";27} else {
  6. std::cout << "reads=" << reads

    31    std::cout << "reads=" << reads232              << " served=" << served233              << " builds=" << builds134              << " value=" << cached4235              << " " << statuscached << std::endl;36    return 0;37}
    outputreads=2 served=2 builds=1 value=42 cached