COMS W4995 C++ Deep Dive for C Programmers

Index of 2026-9/code/18

Parent directory
async.cpp
concur.cpp
cond-var.cpp
future1.cpp
future2.cpp
Makefile
pthread.cpp

async.cpp

#include <iostream>
#include <future>
using namespace std;

int main() {
    future<int> score_future = async(launch::async,
        [] {
            string line;
            int attempts = 0;
            cin.exceptions(ios::failbit | ios::badbit);
            do {
                cout << "Guess my word: ";
                getline(cin, line);
                ++attempts;
            } while (line != "banana");

            return attempts;
        }
    );

    try {
        int final_score = score_future.get();
        cout << "It took you " << final_score << " attempts!\n";
    } catch (const exception& e) {
        cout << "Exception from worker thread: " << e.what() << '\n';
    }
}

concur.cpp

#include <iostream>
#include <chrono>
#include <thread>
#include <mutex>

using namespace std;
using namespace std::chrono;

struct wallet {
    mutex m;
    uint64_t money = 0;
    operator uint64_t() const { return money; }

    wallet& operator++() {
        m.lock();
        ++money;
        m.unlock();

        // {
        //     scoped_lock lck{m};
        //     ++money;
        // }

        return *this;
    }
};

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();

    // {
    //     jthread t1 { f, ref(sum), count };
    //     jthread t2 { f, ref(sum), count };
    // }

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

cond-var.cpp

#include <iostream>
#include <thread>
#include <mutex>
#include <condition_variable>
using namespace std;

int main() {
    mutex mtx;
    condition_variable done;

    int final_score = 0;

    jthread t {
        [&]() {
            string line;
            int attempts = 0;
            do {
                cout << "Guess my word: ";
                getline(cin, line);
                ++attempts;
            } while (line != "banana");

            {
                unique_lock lck(mtx);
                final_score = attempts;
                done.notify_one();
            }
        }
    };

    {
        unique_lock lck(mtx);
        while (final_score == 0) {
            done.wait(lck);
        }
        // Instead of the while loop, we could write this:
        // done.wait(lck, [&] { return final_score != 0; });

        cout << "It took you " << final_score << " attempts!\n";
    }
}

future1.cpp

#include <iostream>
#include <future>
#include <thread>
using namespace std;

int main() {
    promise<int> score_promise;
    future<int> score_future = score_promise.get_future();

    jthread t {
        [&score_promise]() {
            string line;
            int attempts = 0;
            do {
                cout << "Guess my word: ";
                getline(cin, line);
                ++attempts;
            } while (line != "banana");
            score_promise.set_value(attempts);
        }
    };

    int final_score = score_future.get();
    cout << "It took you " << final_score << " attempts!\n";
}

future2.cpp

#include <iostream>
#include <future>
#include <thread>
#include <exception>
using namespace std;

int main() {
    promise<int> score_promise;
    future<int> score_future = score_promise.get_future();

    jthread t {
        [&score_promise]() {
            string line;
            int attempts = 0;
            cin.exceptions(ios::failbit | ios::badbit);
            try {
                do {
                    cout << "Guess my word: ";
                    getline(cin, line);
                    ++attempts;
                } while (line != "banana");
                score_promise.set_value(attempts);
            } catch (...) {
                score_promise.set_exception(current_exception());
            }
        }
    };

    try {
        int final_score = score_future.get();
        cout << "It took you " << final_score << " attempts!\n";
    } catch (const exception& e) {
        cout << "Exception from worker thread: " << e.what() << '\n';
    }
}

Makefile

CC  = g++
CXX = g++

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

LDFLAGS  = -pthread
LDLIBS   =

executables = pthread concur cond-var future1 future2 async

.PHONY: default
default: $(executables)

pthread: pthread.o

concur: concur.o

cond-var: cond-var.o

future1: future1.o

future2: future2.o

async: async.o

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

.PHONY: all
all: clean default

pthread.cpp

#include <iostream>
#include <chrono>
#include <pthread.h>
using namespace std;
using namespace std::chrono;

struct Args {
    uint64_t* sum_ptr;
    uint64_t count;
};

void* f1(void* args) {
    Args* p = (Args*)args;
    uint64_t* sum_ptr = p->sum_ptr;
    uint64_t count = p->count;

    while (count--) {
        ++*sum_ptr;
    }
    return NULL;
}

pthread_mutex_t mtx = PTHREAD_MUTEX_INITIALIZER;

void* f2(void* args) {
    Args* p = (Args*)args;
    uint64_t* sum_ptr = p->sum_ptr;
    uint64_t count = p->count;

    while (count--) {
        pthread_mutex_lock(&mtx);
        ++*sum_ptr;
        pthread_mutex_unlock(&mtx);
    }
    return NULL;
}

uint64_t sum1() {
    constexpr uint64_t count = 1'000'000;
    uint64_t sum = 0;

    Args args1 { &sum, count };
    f1(&args1);

    Args args2 { &sum, count };
    f1(&args2);

    return sum;
}

uint64_t sum2() {
    constexpr uint64_t count = 1'000'000;
    uint64_t sum = 0;
    pthread_t t1, t2;

    Args args1 { &sum, count };
    pthread_create(&t1, NULL, &f1, &args1);

    Args args2 { &sum, count };
    pthread_create(&t2, NULL, &f1, &args2);

    pthread_join(t1, NULL);
    pthread_join(t2, NULL);

    return sum;
}

uint64_t sum3() {
    constexpr uint64_t count = 1'000'000;
    uint64_t sum[2] = {0};
    pthread_t t1, t2;

    Args args1 { &sum[0], count };
    pthread_create(&t1, NULL, &f1, &args1);

    Args args2 { &sum[1], count };
    pthread_create(&t2, NULL, &f1, &args2);

    pthread_join(t1, NULL);
    pthread_join(t2, NULL);

    return sum[0] + sum[1];
}

uint64_t sum4() {
    constexpr uint64_t count = 1'000'000;
    uint64_t sum[9] = {0};
    pthread_t t1, t2;

    Args args1 { &sum[0], count };
    pthread_create(&t1, NULL, &f1, &args1);

    Args args2 { &sum[8], count };
    pthread_create(&t2, NULL, &f1, &args2);

    pthread_join(t1, NULL);
    pthread_join(t2, NULL);

    return sum[0] + sum[8];
}

uint64_t sum5() {
    constexpr uint64_t count = 1'000'000;
    uint64_t sum = 0;
    pthread_t t1, t2;

    Args args1 { &sum, count };
    pthread_create(&t1, NULL, &f2, &args1);

    Args args2 { &sum, count };
    pthread_create(&t2, NULL, &f2, &args2);

    pthread_join(t1, NULL);
    pthread_join(t2, NULL);

    return sum;
}

int main() {
    auto time0 = high_resolution_clock::now();

    uint64_t result = sum1();
    // uint64_t result = sum2();
    // uint64_t result = sum3();
    // uint64_t result = sum4();
    // uint64_t result = sum5();

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