cpp
examples
examples.cpp⚙️cpp
/**
* Multithreading - Examples
* Compile: g++ -std=c++17 -pthread -Wall examples.cpp -o examples
*/
#include <iostream>
#include <thread>
#include <mutex>
#include <shared_mutex>
#include <condition_variable>
#include <future>
#include <atomic>
#include <vector>
#include <queue>
#include <chrono>
using namespace std;
// ============================================================
// SECTION 1: BASIC THREADS
// ============================================================
void simpleTask(int id) {
cout << " Thread " << id << " running" << endl;
this_thread::sleep_for(chrono::milliseconds(100));
cout << " Thread " << id << " done" << endl;
}
void demoBasicThreads() {
cout << "--- Basic Threads ---\n" << endl;
cout << " Hardware threads: " << thread::hardware_concurrency() << endl;
// Create threads
thread t1(simpleTask, 1);
thread t2(simpleTask, 2);
// Lambda thread
thread t3([]() {
cout << " Lambda thread running" << endl;
});
// Wait for completion
t1.join();
t2.join();
t3.join();
cout << " All threads complete" << endl;
}
// ============================================================
// SECTION 2: MUTEX
// ============================================================
mutex printMutex;
int unsafeCounter = 0;
int safeCounter = 0;
mutex counterMutex;
void unsafeIncrement() {
for (int i = 0; i < 10000; i++) {
unsafeCounter++;
}
}
void safeIncrement() {
for (int i = 0; i < 10000; i++) {
lock_guard<mutex> lock(counterMutex);
safeCounter++;
}
}
void demoMutex() {
cout << "\n--- Mutex ---\n" << endl;
// Unsafe (race condition)
unsafeCounter = 0;
vector<thread> threads;
for (int i = 0; i < 10; i++) {
threads.emplace_back(unsafeIncrement);
}
for (auto& t : threads) t.join();
cout << " Unsafe counter: " << unsafeCounter
<< " (expected 100000)" << endl;
// Safe (with mutex)
threads.clear();
safeCounter = 0;
for (int i = 0; i < 10; i++) {
threads.emplace_back(safeIncrement);
}
for (auto& t : threads) t.join();
cout << " Safe counter: " << safeCounter << endl;
}
// ============================================================
// SECTION 3: UNIQUE_LOCK
// ============================================================
mutex flexMutex;
void demoUniqueLock() {
cout << "\n--- unique_lock ---\n" << endl;
unique_lock<mutex> lock(flexMutex);
cout << " Lock acquired" << endl;
// Can release and reacquire
lock.unlock();
cout << " Lock released" << endl;
// Do something without lock...
lock.lock();
cout << " Lock reacquired" << endl;
// Deferred locking
unique_lock<mutex> lock2(flexMutex, defer_lock);
cout << " Deferred lock created (not locked yet)" << endl;
lock2.lock();
cout << " Deferred lock now locked" << endl;
}
// ============================================================
// SECTION 4: CONDITION VARIABLE
// ============================================================
mutex cvMutex;
condition_variable cv;
bool dataReady = false;
string sharedData;
void producer() {
this_thread::sleep_for(chrono::milliseconds(500));
{
lock_guard<mutex> lock(cvMutex);
sharedData = "Data from producer";
dataReady = true;
}
cv.notify_one();
}
void consumer() {
unique_lock<mutex> lock(cvMutex);
cv.wait(lock, []{ return dataReady; });
cout << " Consumer received: " << sharedData << endl;
}
void demoConditionVariable() {
cout << "\n--- Condition Variable ---\n" << endl;
dataReady = false;
thread prod(producer);
thread cons(consumer);
prod.join();
cons.join();
}
// ============================================================
// SECTION 5: PRODUCER-CONSUMER QUEUE
// ============================================================
queue<int> taskQueue;
mutex queueMutex;
condition_variable queueCV;
bool finished = false;
void producerTask() {
for (int i = 1; i <= 5; i++) {
{
lock_guard<mutex> lock(queueMutex);
taskQueue.push(i);
cout << " Produced: " << i << endl;
}
queueCV.notify_one();
this_thread::sleep_for(chrono::milliseconds(100));
}
{
lock_guard<mutex> lock(queueMutex);
finished = true;
}
queueCV.notify_all();
}
void consumerTask(int id) {
while (true) {
unique_lock<mutex> lock(queueMutex);
queueCV.wait(lock, []{ return !taskQueue.empty() || finished; });
if (taskQueue.empty() && finished) break;
int val = taskQueue.front();
taskQueue.pop();
lock.unlock();
cout << " Consumer " << id << " processed: " << val << endl;
}
}
void demoProducerConsumer() {
cout << "\n--- Producer-Consumer ---\n" << endl;
// Reset state
while (!taskQueue.empty()) taskQueue.pop();
finished = false;
thread prod(producerTask);
thread cons1(consumerTask, 1);
thread cons2(consumerTask, 2);
prod.join();
cons1.join();
cons2.join();
}
// ============================================================
// SECTION 6: ASYNC AND FUTURES
// ============================================================
int heavyComputation(int n) {
cout << " Computing in thread " << this_thread::get_id() << endl;
this_thread::sleep_for(chrono::milliseconds(500));
return n * n;
}
void demoAsync() {
cout << "\n--- Async and Futures ---\n" << endl;
cout << " Main thread: " << this_thread::get_id() << endl;
// Launch async task
future<int> result1 = async(launch::async, heavyComputation, 5);
future<int> result2 = async(launch::async, heavyComputation, 10);
cout << " Doing other work while computing..." << endl;
// Get results (blocks if not ready)
cout << " Result 1: " << result1.get() << endl;
cout << " Result 2: " << result2.get() << endl;
}
// ============================================================
// SECTION 7: PROMISE AND FUTURE
// ============================================================
void workerWithPromise(promise<string> p) {
this_thread::sleep_for(chrono::milliseconds(300));
p.set_value("Result from worker");
}
void demoPromise() {
cout << "\n--- Promise and Future ---\n" << endl;
promise<string> p;
future<string> f = p.get_future();
thread t(workerWithPromise, move(p));
cout << " Waiting for result..." << endl;
string result = f.get();
cout << " Got: " << result << endl;
t.join();
}
// ============================================================
// SECTION 8: ATOMIC OPERATIONS
// ============================================================
atomic<int> atomicCounter(0);
void atomicIncrement() {
for (int i = 0; i < 10000; i++) {
atomicCounter++;
}
}
void demoAtomic() {
cout << "\n--- Atomic Operations ---\n" << endl;
atomicCounter = 0;
vector<thread> threads;
for (int i = 0; i < 10; i++) {
threads.emplace_back(atomicIncrement);
}
for (auto& t : threads) t.join();
cout << " Atomic counter: " << atomicCounter << endl;
// Atomic operations
atomicCounter.store(100);
cout << " After store(100): " << atomicCounter.load() << endl;
int old = atomicCounter.exchange(200);
cout << " Exchange returned: " << old << ", new value: "
<< atomicCounter << endl;
// Compare and swap
int expected = 200;
bool success = atomicCounter.compare_exchange_strong(expected, 300);
cout << " CAS success: " << boolalpha << success
<< ", value: " << atomicCounter << endl;
}
// ============================================================
// MAIN
// ============================================================
int main() {
cout << "╔══════════════════════════════════════╗" << endl;
cout << "║ MULTITHREADING - EXAMPLES ║" << endl;
cout << "╚══════════════════════════════════════╝" << endl;
demoBasicThreads();
demoMutex();
demoUniqueLock();
demoConditionVariable();
demoProducerConsumer();
demoAsync();
demoPromise();
demoAtomic();
cout << "\n=== Complete ===" << endl;
return 0;
}