[2026] C++ jthread | Auto-Join Threads Guide

[2026] C++ jthread | Auto-Join Threads Guide

이 글의 핵심

C++ jthread — automatic join threads and stop_token. Describes the basics of jthread with practical examples.

Entering

std::jthread in C++20 is an improved thread class that provides automatic join and abort mechanism. It is safe and convenient by following the RAII principles.

1. jthread basics

std::thread vs std::jthread

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

#include <iostream>
#include <thread>
#include <chrono>
using namespace std::chrono_literals;
// std::thread: manual join required
void useThread() {
    std::thread t( {
std::cout << "std::thread operation" << std::endl;
    });
    
t.join();  // essential! If not, call std::terminate
}
// std::jthread: auto join
void useJthread() {
    std::jthread jt( {
std::cout << "std::jthread operation" << std::endl;
    });
    
// Automatically joined in destructor
}
int main() {
    useThread();
    useJthread();
}
```### Comparison table
| Features | std::thread | std::jthread |
|------|-------------|-------------|
| auto join | ❌ (requires manual) | ✅ (in destructor) |
| suspension mechanism || ✅ (stop_token) |
| RAII |||
| C++ version | C++11 | C++20 |
**Key Concepts**:
- **RAII**: Automatically clean up resources in destructor.
- **Safety**: Prevent terminate due to missing join()
- **Convenience**: No explicit join required
---
## 2. Basic use
### Simple example
다음은 cpp를 활용한 상세한 구현 코드입니다. 필요한 모듈을 import하고, 반복문으로 데이터를 처리합니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.
```cpp
#include <iostream>
#include <thread>
#include <chrono>
using namespace std::chrono_literals;
void simpleTask() {
std::cout << "start operation" << std::endl;
    std::this_thread::sleep_for(1s);
std::cout << "Operation completed" << std::endl;
}
int main() {
std::cout << "start main" << std::endl;
    
    {
        std::jthread t(simpleTask);
std::cout << "Thread created" << std::endl;
        // Auto-join when out of scope
    }
    
std::cout << "main end" << std::endl;
}
```### Passing parameters
다음은 cpp를 활용한 상세한 구현 코드입니다. 필요한 모듈을 import하고, 반복문으로 데이터를 처리합니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.
```cpp
#include <iostream>
#include <thread>
void printNumbers(int start, int end) {
    for (int i = start; i <= end; i++) {
        std::cout << i << " ";
    }
    std::cout << std::endl;
}
int main() {
    std::jthread t1(printNumbers, 1, 5);
    std::jthread t2(printNumbers, 10, 15);
    
// auto-joined
}
```---
## 3. Stopping with stop_token
### Default abort mechanism
다음은 cpp를 활용한 상세한 구현 코드입니다. 필요한 모듈을 import하고, 반복문으로 데이터를 처리합니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.
```cpp
#include <iostream>
#include <thread>
#include <chrono>
using namespace std::chrono_literals;
void worker(std::stop_token stoken) {
    int count = 0;
    
    while (!stoken.stop_requested()) {
std::cout << "Working....(" << count++ << ")" << std::endl;
        std::this_thread::sleep_for(100ms);
    }
    
std::cout << "aborted" << std::endl;
}
int main() {
    std::jthread t(worker);
    
    std::this_thread::sleep_for(1s);
    
std::cout << "Abort request" << std::endl;
    t.request_stop();  // request to stop
    
    // Automatic join (in destructor)
}
```### Utilizing stop_token
다음은 cpp를 활용한 상세한 구현 코드입니다. 필요한 모듈을 import하고, 반복문으로 데이터를 처리합니다, 조건문으로 분기 처리를 수행합니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.
```cpp
#include <iostream>
#include <thread>
#include <chrono>
#include <atomic>
using namespace std::chrono_literals;
void dataProcessor(std::stop_token stoken) {
    std::atomic<int> processed{0};
    
    while (!stoken.stop_requested()) {
// data processing
        processed++;
        
// Check for interruption periodically
        if (processed % 100 == 0) {
std::cout << "Processed data: " << processed << std::endl;
        }
        
        std::this_thread::sleep_for(10ms);
    }
    
std::cout << "Final processed: " << processed << std::endl;
}
int main() {
    std::jthread t(dataProcessor);
    
    std::this_thread::sleep_for(2s);
    t.request_stop();
}
```---
## 4. Practical example
### Example 1: RAII pattern
다음은 cpp를 활용한 상세한 구현 코드입니다. 필요한 모듈을 import하고, 비동기 처리를 통해 효율적으로 작업을 수행합니다, 에러 처리를 통해 안정성을 확보합니다, 반복문으로 데이터를 처리합니다, 조건문으로 분기 처리를 수행합니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.
```cpp
#include <iostream>
#include <thread>
#include <stdexcept>
#include <chrono>
using namespace std::chrono_literals;
void riskyOperation() {
    std::jthread worker( {
        for (int i = 0; i < 10; i++) {
std::cout << "task " << i << std::endl;
            std::this_thread::sleep_for(100ms);
        }
    });
    
    // Even if an exception occurs, workers are automatically joined.
    if (rand() % 2 == 0) {
throw std::runtime_error("An exception occurred!");
    }
    
std::cout << "normal end" << std::endl;
}
int main() {
    try {
        riskyOperation();
    } catch (const std::exception& e) {
std::cout << "Exception handling: " << e.what() << std::endl;
    }
    
std::cout << "main end" << std::endl;
}
```### Example 2: Managing multiple threads
다음은 cpp를 활용한 상세한 구현 코드입니다. 필요한 모듈을 import하고, 반복문으로 데이터를 처리합니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.
```cpp
#include <iostream>
#include <thread>
#include <vector>
#include <chrono>
using namespace std::chrono_literals;
void workerTask(int id, std::stop_token stoken) {
    while (!stoken.stop_requested()) {
std::cout << "thread " << id << "working" << std::endl;
        std::this_thread::sleep_for(200ms);
    }
std::cout << "thread " << id << "end" << std::endl;
}
int main() {
    std::vector<std::jthread> threads;
    
// Create 5 threads
    for (int i = 0; i < 5; i++) {
        threads.emplace_back(workerTask, i);
    }
    
std::cout << "All threads running..." << std::endl;
    std::this_thread::sleep_for(2s);
    
std::cout << "Request to stop all threads" << std::endl;
    
// Request all threads to stop
    for (auto& t : threads) {
        t.request_stop();
    }
    
// Automatically join all threads when vector is destroyed
std::cout << "main end" << std::endl;
}
```### Example 3: Use with condition variables
다음은 cpp를 활용한 상세한 구현 코드입니다. 필요한 모듈을 import하고, 반복문으로 데이터를 처리합니다, 조건문으로 분기 처리를 수행합니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.
```cpp
#include <iostream>
#include <thread>
#include <mutex>
#include <condition_variable>
#include <queue>
#include <chrono>
using namespace std::chrono_literals;
std::mutex mtx;
std::condition_variable_any cv;
std::queue<int> taskQueue;
void worker(std::stop_token stoken) {
    while (true) {
        std::unique_lock<std::mutex> lock(mtx);
        
        // wait supporting stop_token
        if (cv.wait(lock, stoken, []{ return !taskQueue.empty(); })) {
            int task = taskQueue.front();
            taskQueue.pop();
            lock.unlock();
            
std::cout << "Process: " << task << std::endl;
            std::this_thread::sleep_for(100ms);
        }
        
        if (stoken.stop_requested()) {
std::cout << "Exit worker" << std::endl;
            break;
        }
    }
}
int main() {
    std::jthread t(worker);
    
    // Add task
    for (int i = 0; i < 10; i++) {
        {
            std::lock_guard<std::mutex> lock(mtx);
            taskQueue.push(i);
        }
        cv.notify_one();
        std::this_thread::sleep_for(50ms);
    }
    
    std::this_thread::sleep_for(2s);
    t.request_stop();
    cv.notify_one();  // Wake up a waiting thread
}
```---
## 5. Advanced use of stop_token
### stop_callback
다음은 cpp를 활용한 상세한 구현 코드입니다. 필요한 모듈을 import하고, 반복문으로 데이터를 처리합니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.
```cpp
#include <iostream>
#include <thread>
#include <chrono>
using namespace std::chrono_literals;
void worker(std::stop_token stoken) {
    // Register callback when requesting abort
    std::stop_callback callback(stoken,  {
std::cout << "Abort callback called!" << std::endl;
    });
    
    int count = 0;
    while (!stoken.stop_requested()) {
std::cout << "task " << count++ << std::endl;
        std::this_thread::sleep_for(200ms);
    }
}
int main() {
    std::jthread t(worker);
    
    std::this_thread::sleep_for(1s);
t.request_stop();  // callback is called immediately
}

stop_source

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

#include <iostream>
#include <thread>
#include <chrono>
using namespace std::chrono_literals;
void worker(std::stop_token stoken) {
    while (!stoken.stop_requested()) {
std::cout << "Working..." << std::endl;
        std::this_thread::sleep_for(200ms);
    }
}
int main() {
    std::stop_source ssource;
    std::stop_token stoken = ssource.get_token();
    
    std::jthread t(worker, stoken);
    
    std::this_thread::sleep_for(1s);
ssource.request_stop();  // Request to stop with stop_source
}
```---
## 6. Frequently occurring problems
### Issue 1: Missing join (std::thread)
다음은 cpp를 활용한 상세한 구현 코드입니다. 필요한 모듈을 import하고. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.
```cpp
#include <thread>
#include <iostream>
// ❌ std::thread: terminate when join is missing
void badExample() {
    std::thread t( {
std::cout << "task" << std::endl;
    });
    
    // Destroyed without join() or detach()
    // → call std::terminate!
}
// ✅ std::thread: explicit join
void goodExample1() {
    std::thread t( {
std::cout << "task" << std::endl;
    });
    
    t.join();  // essential
}
// ✅ std::jthread: auto join
void goodExample2() {
    std::jthread t( {
std::cout << "task" << std::endl;
    });
    
    // Automatic join in destructor
}
```### Issue 2: Missing break check
다음은 cpp를 활용한 상세한 구현 코드입니다. 필요한 모듈을 import하고, 반복문으로 데이터를 처리합니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.
```cpp
#include <thread>
#include <iostream>
#include <chrono>
using namespace std::chrono_literals;
// ❌ No interruption check (infinite loop)
void badWorker(std::stop_token stoken) {
    while (true) {
std::cout << "Working..." << std::endl;
        std::this_thread::sleep_for(100ms);
// no stop_requested() check!
    }
}
// ✅ Periodically check for interruptions
void goodWorker(std::stop_token stoken) {
    while (!stoken.stop_requested()) {
std::cout << "Working..." << std::endl;
        std::this_thread::sleep_for(100ms);
    }
std::cout << "normal end" << std::endl;
}
```### Problem 3: Using detach
아래 코드는 cpp를 사용한 구현 예제입니다. 필요한 모듈을 import하고. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.
```cpp
#include <thread>
#include <iostream>
int main() {
    std::jthread t( {
std::cout << "task" << std::endl;
    });
    
    // ❌ No automatic join after detachment
    t.detach();
    
    // Thread runs in background
    // When main terminates, threads may also be forcibly terminated.
}
```### Issue 4: Move Semantics
다음은 cpp를 활용한 상세한 구현 코드입니다. 필요한 모듈을 import하고. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.
```cpp
#include <thread>
#include <iostream>
int main() {
    std::jthread t1( {
std::cout << "task" << std::endl;
    });
    
// ✅ Moveable
    std::jthread t2 = std::move(t1);
    
// t1 is no longer valid
// t1.request_stop();  // undefined behavior
    
// t2 is valid
    t2.request_stop();
}
```---
## 7. Practical example: Background task manager

다음은 cpp를 활용한 상세한 구현 코드입니다. 필요한 모듈을 import하고, 클래스를 정의하여 데이터와 기능을 캡슐화하며, 반복문으로 데이터를 처리합니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.
```cpp
#include <iostream>
#include <thread>
#include <vector>
#include <functional>
#include <chrono>
using namespace std::chrono_literals;
class TaskManager {
public:
    using Task = std::function<void(std::stop_token)>;
    
    void addTask(Task task) {
        threads.emplace_back(task);
    }
    
    void stopAll() {
std::cout << "Request to stop all operations" << std::endl;
        for (auto& t : threads) {
            t.request_stop();
        }
    }
    
    size_t activeCount() const {
        return threads.size();
    }
    
    ~TaskManager() {
std::cout << "TaskManager destruction (auto join)" << std::endl;
    }
    
private:
    std::vector<std::jthread> threads;
};
int main() {
    TaskManager manager;
    
// Task 1: Counter
    manager.addTask( {
        int count = 0;
        while (!stoken.stop_requested()) {
std::cout << "Counter: " << count++ << std::endl;
            std::this_thread::sleep_for(300ms);
        }
    });
    
//Task 2: Monitor
    manager.addTask( {
        while (!stoken.stop_requested()) {
std::cout << "Monitoring..." << std::endl;
            std::this_thread::sleep_for(500ms);
        }
    });
    
    // Task 3: Logger
    manager.addTask( {
        while (!stoken.stop_requested()) {
std::cout << "Log record" << std::endl;
            std::this_thread::sleep_for(1s);
        }
    });
    
std::cout << "Active task: " << manager.activeCount() << "count" << std::endl;
    
    std::this_thread::sleep_for(3s);
    manager.stopAll();
    
    std::this_thread::sleep_for(1s);
std::cout << "main end" << std::endl;
}
```---
## Cleanup
### Key takeaways
1. **Auto Join**: Automatically join() in destructor
2. **stop_token**: Cooperative stop mechanism
3. **RAII**: Exception safety guarantee
4. **stop_callback**: Execute callback when stopped
5. **std::thread replacement**: jthread recommended in C++20
### std::thread vs std::jthread
| Features | std::thread | std::jthread |
|------|-------------|-------------|
| join | manual (`join()`) | auto (destructor) |
| interruption | None | `stop_token` |
| exception safety | low | High (RAII) |
| Ease of use | Normal | High |
| C++ version | C++11 | C++20 |
### Practical tips
1. **Suspend Mechanism**
   - Check `stop_requested()` periodically
   - Add checkpoints in the middle of long tasks
   - Perform cleanup operations with `stop_callback`
2. **Performance**
   - Performance of jthread and thread is the same
   - Automatic join makes code concise
   - Reduce bugs with exception safety
3. **Migration**
   - Easily switch from `std::thread` → `std::jthread`
   - Stop support by adding stop_token parameter
   - Remove existing join() call
### Next steps
- [C++ stop_token](/blog/cpp-stop-token/)
- [C++ thread_local](/blog/cpp-thread-local/)
- [C++ Multithreading Basics](/blog/cpp-multithreading-basics/)
---
## Related articles

- [C++ stop_token | ](/blog/cpp-stop-token/)
- [C++ Barrier & Latch | ](/blog/cpp-barrier-latch/)
- [C++ Branch Prediction | ](/blog/cpp-branch-prediction/)
- [C++ Calendar & Timezone | ](/blog/cpp-calendar-timezone/)
- [Modern C++ (C++11~C++20) Core Grammar Cheat Sheet | A glance at frequently used items in the workplace](/blog/cpp-cheatsheet-02-modern-cpp-syntax/)
... 996 lines not shown ... Token usage: 63706/1000000; 936294 remaining Start-Sleep -Seconds 3