[2026] C++ Multithreading Basics: std::thread, mutex, and Concurrency

[2026] C++ Multithreading Basics: std::thread, mutex, and Concurrency

이 글의 핵심

Introduction to C++ concurrency: std::thread, join/detach, mutex and lock_guard, producer–consumer patterns, thread pools, races, and deadlocks.

Create default thread

다음은 cpp를 활용한 상세한 구현 코드입니다. 필요한 모듈을 import하고. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

#include <iostream>
#include <thread>
using namespace std;
void printHello() {
    cout << "Hello from thread!" << endl;
}
int main() {
thread t(printHello);// create thread
t.join();// Wait for thread to terminate
    
    cout << "Main thread" << endl;
    
    return 0;
}

Lambda and parameters

다음은 cpp를 활용한 상세한 구현 코드입니다. 필요한 모듈을 import하고. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

#include <iostream>
#include <thread>
using namespace std;
int main() {
// use lambda
    thread t1( {
        cout << "Lambda thread" << endl;
    });
    
// Passing parameters
    thread t2( {
        cout << x << ": " << s << endl;
    }, 10, "Hello");
    
    t1.join();
    t2.join();
    
    return 0;
}

Synchronize with mutex

다음은 cpp를 활용한 상세한 구현 코드입니다. 필요한 모듈을 import하고, 반복문으로 데이터를 처리합니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

#include <iostream>
#include <thread>
#include <mutex>
using namespace std;
mutex mtx;
int counter = 0;
void increment() {
    for (int i = 0; i < 1000; i++) {
        mtx.lock();
        counter++;
        mtx.unlock();
    }
}
int main() {
    thread t1(increment);
    thread t2(increment);
    
    t1.join();
    t2.join();
    
    cout << "Counter: " << counter << endl;  // 2000
    
    return 0;
}

lock_guard (RAII)

다음은 cpp를 활용한 상세한 구현 코드입니다. 필요한 모듈을 import하고, 반복문으로 데이터를 처리합니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

#include <iostream>
#include <thread>
#include <mutex>
using namespace std;
mutex mtx;
void safeIncrement(int& counter) {
    for (int i = 0; i < 1000; i++) {
lock_guard<mutex> lock(mtx);  // unlocks automatically
        counter++;
} // automatically unlocked
}
int main() {
    int counter = 0;
    
    thread t1(safeIncrement, ref(counter));
    thread t2(safeIncrement, ref(counter));
    
    t1.join();
    t2.join();
    
    cout << "Counter: " << counter << endl;  // 2000
    
    return 0;
}

Practical example

Example 1: Parallel computation

다음은 cpp를 활용한 상세한 구현 코드입니다. 필요한 모듈을 import하고, 반복문으로 데이터를 처리합니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

#include <iostream>
#include <thread>
#include <vector>
using namespace std;
void sumRange(int start, int end, long long& result) {
    long long sum = 0;
    for (int i = start; i < end; i++) {
        sum += i;
    }
    result = sum;
}
int main() {
    const int N = 100000000;
    const int NUM_THREADS = 4;
    
    vector<thread> threads;
    vector<long long> results(NUM_THREADS);
    
    int range = N / NUM_THREADS;
    
// create thread
    for (int i = 0; i < NUM_THREADS; i++) {
        int start = i * range;
        int end = (i == NUM_THREADS - 1) ? N : (i + 1) * range;
        threads.emplace_back(sumRange, start, end, ref(results[i]));
    }
    
// wait for all threads
    for (auto& t : threads) {
        t.join();
    }
    
// sum up results
    long long total = 0;
    for (long long r : results) {
        total += r;
    }
    
    cout << "sum: " << total << endl;
    
    return 0;
}

Description: Split large calculations into multiple threads for parallel processing.

Example 2: Producer-Consumer Pattern

다음은 cpp를 활용한 상세한 구현 코드입니다. 필요한 모듈을 import하고, 반복문으로 데이터를 처리합니다, 조건문으로 분기 처리를 수행합니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

#include <iostream>
#include <thread>
#include <queue>
#include <mutex>
#include <condition_variable>
using namespace std;
queue<int> dataQueue;
mutex mtx;
condition_variable cv;
bool done = false;
void producer() {
    for (int i = 1; i <= 10; i++) {
        this_thread::sleep_for(chrono::milliseconds(100));
        
        {
            lock_guard<mutex> lock(mtx);
            dataQueue.push(i);
            cout << "produce: " << i << endl;
        }
        
cv.notify_one();// Notify consumer
    }
    
    {
        lock_guard<mutex> lock(mtx);
        done = true;
    }
    cv.notify_all();
}
void consumer() {
    while (true) {
        unique_lock<mutex> lock(mtx);
        
        cv.wait(lock,  {
            return !dataQueue.empty() || done;
        });
        
        while (!dataQueue.empty()) {
            int value = dataQueue.front();
            dataQueue.pop();
            lock.unlock();
            
            cout << "consume: " << value << endl;
            this_thread::sleep_for(chrono::milliseconds(150));
            
            lock.lock();
        }
        
        if (done && dataQueue.empty()) {
            break;
        }
    }
}
int main() {
    thread prod(producer);
    thread cons(consumer);
    
    prod.join();
    cons.join();
    
    return 0;
}

Description: This is a pattern where a producer and consumer exchange data through a queue.

Example 3: Thread Pool

다음은 cpp를 활용한 상세한 구현 코드입니다. 필요한 모듈을 import하고, 클래스를 정의하여 데이터와 기능을 캡슐화하며, 반복문으로 데이터를 처리합니다, 조건문으로 분기 처리를 수행합니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

#include <iostream>
#include <thread>
#include <vector>
#include <queue>
#include <functional>
#include <mutex>
#include <condition_variable>
using namespace std;
class ThreadPool {
private:
    vector<thread> workers;
    queue<function<void()>> tasks;
    mutex mtx;
    condition_variable cv;
    bool stop;
    
public:
    ThreadPool(size_t numThreads) : stop(false) {
        for (size_t i = 0; i < numThreads; i++) {
            workers.emplace_back([this]() {
                while (true) {
                    function<void()> task;
                    
                    {
                        unique_lock<mutex> lock(mtx);
                        cv.wait(lock, [this]() {
                            return stop || !tasks.empty();
                        });
                        
                        if (stop && tasks.empty()) {
                            return;
                        }
                        
                        task = move(tasks.front());
                        tasks.pop();
                    }
                    
                    task();
                }
            });
        }
    }
    
    ~ThreadPool() {
        {
            unique_lock<mutex> lock(mtx);
            stop = true;
        }
        
        cv.notify_all();
        
        for (auto& worker : workers) {
            worker.join();
        }
    }
    
    void enqueue(function<void()> task) {
        {
            unique_lock<mutex> lock(mtx);
            tasks.push(task);
        }
        cv.notify_one();
    }
};
int main() {
    ThreadPool pool(4);
    
    for (int i = 1; i <= 10; i++) {
        pool.enqueue([i]() {
            cout << "task " << i << " start (thread " 
                 << this_thread::get_id() << ")" << endl;
            this_thread::sleep_for(chrono::seconds(1));
            cout << "task " << i << " done" << endl;
        });
    }
    
    this_thread::sleep_for(chrono::seconds(5));
    
    return 0;
}

Description: Efficiently distributes work to thread pools.

Frequently occurring problems

Problem 1: Race Condition

Symptoms: Results vary each time Cause: Accessing shared resources without synchronization dissolvent: 다음은 cpp를 활용한 상세한 구현 코드입니다. 반복문으로 데이터를 처리합니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

// ❌ Race conditions
int counter = 0;
void increment() {
    for (int i = 0; i < 1000; i++) {
counter++;// danger!
    }
}
// ✅ Protected by mutex
mutex mtx;
int counter = 0;
void increment() {
    for (int i = 0; i < 1000; i++) {
        lock_guard<mutex> lock(mtx);
        counter++;
    }
}

Problem 2: Deadlock

Symptom: Program freezes Cause: Waiting on different mutexes dissolvent: 다음은 cpp를 활용한 상세한 구현 코드입니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

// ❌ Deadlock possible
mutex mtx1, mtx2;
void func1() {
    lock_guard<mutex> lock1(mtx1);
    lock_guard<mutex> lock2(mtx2);
}
void func2() {
lock_guard<mutex> lock2(mtx2);// Different order!
    lock_guard<mutex> lock1(mtx1);
}
// ✅ Always lock in the same order
void func1() {
    lock_guard<mutex> lock1(mtx1);
    lock_guard<mutex> lock2(mtx2);
}
void func2() {
lock_guard<mutex> lock1(mtx1);// same order
    lock_guard<mutex> lock2(mtx2);
}
// ✅ Use scoped_lock (C++17)
void func() {
scoped_lock lock(mtx1, mtx2);// Automatically prevent deadlock
}

Problem 3: See dangling after detach

Symptom: Crashes or strange values Cause: The variable referenced by the thread is destroyed. dissolvent: 다음은 cpp를 활용한 상세한 구현 코드입니다. 반복문으로 데이터를 처리합니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

// ❌ Dangerous code
void badExample() {
    int data = 10;
    thread t([&data]() {
        this_thread::sleep_for(chrono::seconds(1));
cout << data << endl;// Already destroyed!
    });
    t.detach();
} // data destruction
// ✅ Capture by value
void goodExample() {
    int data = 10;
    thread t([data]() {
        this_thread::sleep_for(chrono::seconds(1));
cout << data << endl;// safety
    });
    t.detach();
}
// ✅ Wait with join
void betterExample() {
    int data = 10;
    thread t([&data]() {
        cout << data << endl;
    });
t.join();// atmosphere
}

FAQ

Q1: join vs detach?

A:

  • join: Wait for thread to terminate (recommended)
  • detach: Runs in background (needs caution)

Q2: How many threads should I create?

A: Typically, the number of CPU cores is sufficient.

unsigned int numThreads = thread::hardware_concurrency();

Q3: Are mutexes slow?

A: There is some overhead, but you should definitely use it if necessary.You might also consider atomic.

Q4: Which containers are thread-safe?

A: C++ standard containers are not thread-safe by default.Protect it with a mutex or use a concurrent library.

Q5: async vs thread?

A:

  • thread: low-level control
  • async: high level, simple (returns future) 다음은 간단한 cpp 코드 예제입니다. 비동기 처리를 통해 효율적으로 작업을 수행합니다. 코드를 직접 실행해보면서 동작을 확인해보세요.
auto future = async(launch::async,  {
    return 42;
});
cout << future.get() << endl;

Q6: When to use multithreading?

A:

  • Parallelize CPU-intensive tasks
  • Utilize I/O latency
  • Improved responsiveness (UI)

Good article to read together (internal link)

Here’s another article related to this topic.

Practical tips

These are tips that can be applied right away in practice.

Debugging tips

  • If you run into a problem, check the compiler warnings first.
  • Reproduce the problem with a simple test case

Performance Tips

  • Don’t optimize without profiling
  • Set measurable indicators first

Code review tips

  • Check in advance for areas that are frequently pointed out in code reviews.
  • Follow your team’s coding conventions

Practical checklist

This is what you need to check when applying this concept in practice.

Before writing code

  • Is this technique the best way to solve the current problem?
  • Can team members understand and maintain this code?
  • Does it meet the performance requirements?

Writing code

  • Have you resolved all compiler warnings?
  • Have you considered edge cases?
  • Is error handling appropriate?

When reviewing code

  • Is the intention of the code clear?
  • Are there enough test cases?
  • Is it documented? Use this checklist to reduce mistakes and improve code quality.

Keywords covered in this article (related search terms)

This article will be helpful if you search for C++, multithreading, thread, mutex, concurrency, etc.

... 996 lines not shown ... Token usage: 63706/1000000; 936294 remaining Start-Sleep -Seconds 3