COMS W4995 C++ Deep Dive for C Programmers

Index of 2026-1/code/19

Parent directory
atomic.cpp
Makefile
rel-acq.cpp

atomic.cpp

#include <iostream>
#include <chrono>
#include <thread>
#include <atomic>
using namespace std;
using namespace std::chrono;

struct wallet {
    std::atomic<uint64_t> money{0};
    operator uint64_t() const {
        return money;
        // return money.load(std::memory_order_relaxed);
    }

    wallet& operator++() {
        ++money;
        // money.fetch_add(1, std::memory_order_relaxed);
        return *this;
    }
};

// Built-in types are always lock-free, but custom structures may not be.
// static_assert(atomic<uint64_t>::is_always_lock_free);

void f(wallet& sum, uint64_t count) {
    while (count--) {
        ++sum;
    }
}

int main() {
    constexpr uint64_t count = 1'000'000;
    wallet sum;

    auto time0 = high_resolution_clock::now();

    thread t1 { f, ref(sum), count };
    thread t2 { f, ref(sum), count };
    t1.join();
    t2.join();

    auto time1 = high_resolution_clock::now();
    auto dt = duration_cast<microseconds>(time1 - time0);
    cout << "elapsed: " << dt.count() << " microsec\n";
    cout << "result: " << sum << '\n';
}

Makefile

CC  = g++
CXX = g++

CFLAGS   = -Wall -g
CXXFLAGS = -Wall -g -std=c++20 -pthread

LDFLAGS  = -pthread
LDLIBS   =

executables = atomic

.PHONY: default
default: $(executables)

atomic:

.PHONY: clean
clean:
	rm -f a.out core *.o $(executables)

.PHONY: all
all: clean default

rel-acq.cpp

#include <atomic>
#include <cassert>
#include <string>
#include <thread>
 
std::atomic<uint64_t> x{0};
//uint64_t x{0};
std::atomic<uint64_t> y{0};

void producer() {
    for (size_t i = 0; i < 1000'000'000; ++i) {
        x.fetch_add(1, std::memory_order_relaxed);
        //++x;
        //y.fetch_add(1, std::memory_order_release);
        y.fetch_add(1, std::memory_order_relaxed);
    }
}

void consumer() {
    for (size_t i = 0; i < 1000'000'000; ++i) {
        int64_t yy = y.load(std::memory_order_acquire);
        //uint64_t yy = y.load(std::memory_order_relaxed);
        assert(x.load(std::memory_order_relaxed) >= yy);
        //assert(x >= yy);
    }
}
 
int main()
{
    std::thread t1(producer);
    std::thread t2(consumer);
    t1.join(); 
    t2.join();
}