C++ thread类
C++11 std::thread 构造函数
1. 默认构造函数 (1)
函数声明
cpp
thread() noexcept;
作用
创建一个不关联任何线程的线程对象(空线程对象)
使用示例
cpp
#include <iostream>
#include <thread>
int main() {
// 创建空线程对象
std::thread t1;
// 检查是否关联线程
if (!t1.joinable()) {
std::cout << "t1 is not associated with any thread" << std::endl;
}
// 后续可以通过移动赋值关联线程
std::thread t2([](){
std::cout << "Hello from thread!" << std::endl;
});
t1 = std::move(t2); // 现在 t1 关联线程
if (t1.joinable()) {
t1.join();
}
return 0;
}
注意事项
- 创建的对象不执行任何函数
joinable()返回false- 不能对其调用
join()或detach() - 主要用于后续的移动赋值操作
2. 初始化构造函数 (2)
函数声明
cpp
template <class Fn, class... Args>
explicit thread (Fn&& fn, Args&&... args);
参数说明
fn: 可调用对象(函数、函数指针、成员函数指针、函数对象、lambda表达式等)args...: 传递给可调用对象的参数包
作用
创建新线程并立即开始执行指定的可调用对象
使用示例
普通函数
cpp
void print_message(const std::string& msg, int count) {
for (int i = 0; i < count; ++i) {
std::cout << msg << " (" << i + 1 << "/" << count << ")" << std::endl;
}
}
int main() {
std::thread t(print_message, "Hello Thread", 3);
t.join();
return 0;
}
Lambda 表达式
cpp
int main() {
int x = 10;
std::thread t([x](const std::string& name) {
std::cout << "Hello " << name << ", x = " << x << std::endl;
}, "World");
t.join();
return 0;
}
成员函数
cpp
class Worker {
public:
void process(int id, const std::string& data) {
std::cout << "Worker " << id << " processing: " << data << std::endl;
}
static void static_process(int id) {
std::cout << "Static worker " << id << std::endl;
}
};
int main() {
Worker worker;
// 非静态成员函数:需要传递对象指针/引用
std::thread t1(&Worker::process, &worker, 1, "some data");
// 静态成员函数:与普通函数相同
std::thread t2(&Worker::static_process, 2);
t1.join();
t2.join();
return 0;
}
函数对象(Functor)
cpp
struct Counter {
void operator()(int max) {
for (int i = 1; i <= max; ++i) {
std::cout << "Count: " << i << "/" << max << std::endl;
}
}
};
int main() {
Counter counter;
std::thread t(counter, 5); // 或者直接 std::thread t(Counter(), 5);
t.join();
return 0;
}
参数传递细节
值传递(默认)
cpp
void modify_value(int val) {
val = 100; // 只修改副本
}
int main() {
int x = 50;
std::thread t(modify_value, x);
t.join();
std::cout << "x = " << x << std::endl; // 输出 50(未改变)
return 0;
}
引用传递(使用 std::ref)
cpp
void modify_value(int& val) {
val = 100;
}
int main() {
int x = 50;
std::thread t(modify_value, std::ref(x)); // 必须使用 std::ref
t.join();
std::cout << "x = " << x << std::endl; // 输出 100(已改变)
return 0;
}
移动语义
cpp
void process_vector(std::vector<int>&& data) {
std::cout << "Processing vector with " << data.size() << " elements" << std::endl;
}
int main() {
std::vector<int> large_data(1000000, 42);
// 使用 std::move 避免拷贝
std::thread t(process_vector, std::move(large_data));
t.join();
std::cout << "Original vector size: " << large_data.size() << std::endl; // 输出 0
return 0;
}
3. 拷贝构造函数 [deleted] (3)
函数声明
cpp
thread (const thread&) = delete;
作用
明确表示线程对象不可拷贝(编译时错误)
使用示例
cpp
std::thread t1([](){
std::cout << "Thread 1" << std::endl;
});
// 编译错误:尝试拷贝线程对象
// std::thread t2 = t1; // ERROR!
// 编译错误:拷贝构造
// std::thread t2(t1); // ERROR!
设计原因
- 防止多个线程对象管理同一个线程
- 确保线程资源的唯一所有权
- 避免资源管理混乱
4. 移动构造函数 (4)
函数声明
cpp
thread (thread&& x) noexcept;
作用
将线程所有权从一个对象转移到另一个对象
使用示例
cpp
void worker() {
std::cout << "Working in thread " << std::this_thread::get_id() << std::endl;
}
int main() {
std::thread t1(worker);
// 移动构造:转移线程所有权
std::thread t2 = std::move(t1);
// t1 不再拥有线程
if (!t1.joinable()) {
std::cout << "t1 is no longer joinable" << std::endl;
}
// t2 现在拥有线程
if (t2.joinable()) {
t2.join();
}
return 0;
}
移动语义的实际应用
cpp
class ThreadPool {
std::vector<std::thread> workers;
public:
void add_worker(std::thread&& t) {
workers.push_back(std::move(t)); // 移动线程到容器中
}
void wait_all() {
for (auto& t : workers) {
if (t.joinable()) {
t.join();
}
}
}
};
int main() {
ThreadPool pool;
// 创建并移动线程到线程池
pool.add_worker(std::thread([](){
std::cout << "Worker 1" << std::endl;
}));
pool.add_worker(std::thread([](){
std::cout << "Worker 2" << std::endl;
}));
pool.wait_all();
return 0;
}
重要注意事项和使用细节
1. 线程对象生命周期管理
cpp
// 危险:临时线程对象立即析构
std::thread([]{
std::this_thread::sleep_for(std::chrono::seconds(1));
std::cout << "This may not execute!" << std::endl;
}); // 立即析构,可能终止程序
// 正确:管理线程对象生命周期
{
std::thread t([]{
std::this_thread::sleep_for(std::chrono::seconds(1));
std::cout << "This will execute properly" << std::endl;
});
t.detach(); // 或者 t.join()
}
2. 异常安全
cpp
void risky_operation() {
std::thread t([](){
// 一些工作
});
// 如果这里抛出异常,t 可能没有被 join/detach
// throw std::runtime_error("Something went wrong");
// 解决方案:使用 RAII
if (t.joinable()) {
t.join();
}
}
// RAII 包装器
class ThreadGuard {
std::thread& t;
public:
explicit ThreadGuard(std::thread& t_) : t(t_) {}
~ThreadGuard() {
if (t.joinable()) {
t.join();
}
}
ThreadGuard(const ThreadGuard&) = delete;
ThreadGuard& operator=(const ThreadGuard&) = delete;
};
3. 参数求值顺序
cpp
void print_values(int a, int b) {
std::cout << "a = " << a << ", b = " << b << std::endl;
}
int get_value() {
static int counter = 0;
return ++counter;
}
int main() {
// 参数求值顺序未定义,可能是 (1,2) 或 (2,1)
std::thread t(print_values, get_value(), get_value());
t.join();
return 0;
}
4. 返回值处理
线程函数不能直接返回值,需要使用 std::promise和 std::future:
cpp
#include <future>
int compute() {
return 42;
}
int main() {
std::packaged_task<int()> task(compute);
std::future<int> result = task.get_future();
std::thread t(std::move(task));
t.join();
std::cout << "Result: " << result.get() << std::endl;
return 0;
}
总结
| 构造函数 | 作用 | 关键点 |
|---|---|---|
| 默认构造 | 创建空线程对象 | joinable() == false |
| 初始化构造 | 创建并启动线程 | 参数按值传递,引用需用 std::ref |
| 拷贝构造 | 已删除 | 防止多个对象管理同一线程 |
| 移动构造 | 转移线程所有权 | 原对象变为空线程对象 |
最佳实践:
- 总是检查
joinable()后再调用join()或detach() - 使用 RAII 模式管理线程生命周期
- 避免在线程间共享数据,或使用适当的同步机制
- 优先使用移动语义而非创建临时线程
C++11 std::thread 赋值运算符
1. 移动赋值运算符 (1)
函数声明
cpp
thread& operator= (thread&& rhs) noexcept;
参数说明
rhs: 右值引用,指向要移动的源线程对象
返回值
- 返回当前对象的引用(
*this) - 支持链式赋值操作
作用
将另一个线程对象的所有权移动到当前对象
使用示例
基本移动赋值
cpp
#include <iostream>
#include <thread>
void worker(int id) {
std::cout << "Worker " << id << " executing in thread "
<< std::this_thread::get_id() << std::endl;
}
int main() {
std::thread t1; // 默认构造,空线程对象
// 创建有工作的线程对象
std::thread t2(worker, 1);
std::cout << "Before move assignment:" << std::endl;
std::cout << "t1 joinable: " << t1.joinable() << std::endl; // 0
std::cout << "t2 joinable: " << t2.joinable() << std::endl; // 1
// 移动赋值:将 t2 的所有权转移给 t1
t1 = std::move(t2);
std::cout << "\nAfter move assignment:" << std::endl;
std::cout << "t1 joinable: " << t1.joinable() << std::endl; // 1
std::cout << "t2 joinable: " << t2.joinable() << std::endl; // 0
if (t1.joinable()) {
t1.join();
}
return 0;
}
自赋值安全性
cpp
std::thread t(worker, 1);
// 自赋值检查:标准要求是安全的
t = std::move(t); // 自赋值,标准要求无操作
if (t.joinable()) {
t.join(); // 仍然可以正常 join
}
链式赋值
cpp
std::thread t1, t2, t3;
// 链式移动赋值
t1 = std::move(t2 = std::move(std::thread(worker, 1)));
if (t1.joinable()) {
t1.join();
}
移动语义的实际应用场景
线程池中的线程管理
cpp
#include <vector>
#include <functional>
class ThreadPool {
private:
std::vector<std::thread> workers;
public:
// 添加工作线程到线程池
void add_worker(std::thread&& new_worker) {
workers.push_back(std::thread()); // 先添加空线程
workers.back() = std::move(new_worker); // 移动赋值
}
// 等待所有线程完成
void wait_all() {
for (auto& worker : workers) {
if (worker.joinable()) {
worker.join();
}
}
workers.clear();
}
~ThreadPool() {
wait_all();
}
};
int main() {
ThreadPool pool;
// 创建并移动线程到线程池
std::thread t1([](){
std::cout << "Worker 1 started" << std::endl;
std::this_thread::sleep_for(std::chrono::milliseconds(100));
std::cout << "Worker 1 finished" << std::endl;
});
pool.add_worker(std::move(t1));
// 直接创建临时线程对象
pool.add_worker(std::thread([](){
std::cout << "Worker 2 started" << std::endl;
std::this_thread::sleep_for(std::chrono::milliseconds(200));
std::cout << "Worker 2 finished" << std::endl;
}));
pool.wait_all();
return 0;
}
线程所有权的动态转移
cpp
class ThreadManager {
private:
std::thread current_thread;
public:
// 启动新线程,自动管理旧线程
void start_new_task(std::function<void()> task) {
// 如果有正在运行的线程,等待它完成
if (current_thread.joinable()) {
std::cout << "Waiting for previous thread to complete..." << std::endl;
current_thread.join();
}
// 移动赋值新线程
current_thread = std::thread(task);
std::cout << "New thread started" << std::endl;
}
void wait_current() {
if (current_thread.joinable()) {
current_thread.join();
}
}
~ThreadManager() {
wait_current();
}
};
int main() {
ThreadManager manager;
manager.start_new_task([](){
std::cout << "Task 1 running..." << std::endl;
std::this_thread::sleep_for(std::chrono::milliseconds(500));
std::cout << "Task 1 completed" << std::endl;
});
std::this_thread::sleep_for(std::chrono::milliseconds(100));
manager.start_new_task([](){
std::cout << "Task 2 running..." << std::endl;
std::this_thread::sleep_for(std::chrono::milliseconds(300));
std::cout << "Task 2 completed" << std::endl;
});
manager.wait_current();
return 0;
}
2. 拷贝赋值运算符 [deleted] (2)
函数声明
cpp
thread& operator= (const thread&) = delete;
作用
明确禁止线程对象的拷贝赋值操作
设计原因
- 确保线程资源的唯一所有权
- 防止多个线程对象管理同一个底层线程
- 避免资源管理混乱和竞态条件
使用示例(错误演示)
cpp
std::thread t1([]{
std::cout << "Thread 1" << std::endl;
});
// 编译错误:尝试拷贝赋值
// std::thread t2;
// t2 = t1; // ERROR: use of deleted function
// 编译错误:拷贝构造也是被删除的
// std::thread t3 = t1; // ERROR: use of deleted function
t1.join();
重要注意事项和使用细节
1. 自我赋值安全性
cpp
std::thread t(worker, 1);
// 标准要求移动赋值运算符必须处理自我赋值
t = std::move(t); // 安全的,t 仍然有效
if (t.joinable()) {
t.join(); // 正常工作
}
2. 移动后的源对象状态
cpp
std::thread t1(worker, 1);
std::thread t2;
t2 = std::move(t1); // 移动赋值
// t1 现在处于"空"状态
std::cout << "t1 joinable: " << t1.joinable() << std::endl; // 0
std::cout << "t2 joinable: " << t2.joinable() << std::endl; // 1
// 对 t1 的操作是安全的但无效
t1.detach(); // 无操作,不会崩溃
t1.join(); // 无操作,不会崩溃
// 只有 t2 需要管理
t2.join();
3. 异常安全性
cpp
void exception_safe_example() {
std::thread t1(worker, 1);
std::thread t2;
try {
// 移动赋值是 noexcept 的,不会抛出异常
t2 = std::move(t1);
// 这里可能抛出异常
throw std::runtime_error("Something went wrong");
} catch (const std::exception& e) {
std::cout << "Exception: " << e.what() << std::endl;
// 异常安全:只需要管理 t2
if (t2.joinable()) {
t2.join();
}
// t1 已经是空状态,无需管理
}
}
4. 资源管理模式
RAII 包装器示例
cpp
class ScopedThread {
std::thread t;
public:
// 移动构造
ScopedThread(std::thread&& t_) : t(std::move(t_)) {}
// 移动赋值
ScopedThread& operator=(std::thread&& other) {
// 先等待当前线程(如果有)
if (t.joinable()) {
t.join();
}
// 移动新线程
t = std::move(other);
return *this;
}
// 禁止拷贝
ScopedThread(const ScopedThread&) = delete;
ScopedThread& operator=(const ScopedThread&) = delete;
// 析构函数自动 join
~ScopedThread() {
if (t.joinable()) {
t.join();
}
}
// 显式等待接口
void wait() {
if (t.joinable()) {
t.join();
}
}
bool joinable() const { return t.joinable(); }
};
int main() {
ScopedThread st(std::thread(worker, 1));
// 可以重新赋值(移动语义)
st = std::thread(worker, 2);
// 析构时自动 join
return 0;
}
5. 容器中的线程管理
cpp
// 在标准容器中存储线程对象
std::vector<std::thread> thread_pool;
// 正确:使用移动语义添加线程
thread_pool.push_back(std::thread(worker, 1));
thread_pool.emplace_back(worker, 2);
// 错误:不能拷贝
// thread_pool.push_back(thread_pool[0]); // 编译错误
// 正确:移动容器中的线程
std::thread temp = std::move(thread_pool[0]);
thread_pool[0] = std::move(thread_pool[1]);
thread_pool[1] = std::move(temp);
// 等待所有线程
for (auto& t : thread_pool) {
if (t.joinable()) {
t.join();
}
}
thread_pool.clear();
6. 条件赋值模式
cpp
class ConditionalThreadManager {
std::thread worker_thread;
bool should_restart = false;
public:
void start_or_restart(std::function<void()> task) {
if (worker_thread.joinable()) {
// 如果线程正在运行,标记需要重启
should_restart = true;
worker_thread.join(); // 等待当前线程完成
}
// 使用移动赋值启动新线程
worker_thread = std::thread([this, task]() {
task();
if (should_restart) {
should_restart = false;
// 可以在这里重新启动任务
}
});
}
~ConditionalThreadManager() {
if (worker_thread.joinable()) {
worker_thread.join();
}
}
};
总结
移动赋值运算符的关键特性
| 特性 | 说明 |
|---|---|
| 参数 | thread&& rhs(右值引用) |
| 返回值 | thread&(支持链式赋值) |
| 异常规范 | noexcept(不抛出异常) |
| 自赋值安全 | 是(标准要求) |
| 移动后状态 | 源对象变为空线程对象 |
拷贝赋值运算符
- 被显式删除(
= delete) - 任何拷贝赋值尝试都会导致编译错误
- 设计目的是确保线程所有权的唯一性
最佳实践
-
总是检查移动后的状态
cppt2 = std::move(t1); // t1 现在为空,只能进行无操作调用 -
利用 RAII 模式
// 使用包装类自动管理线程生命周期 -
异常安全编程
// 移动赋值不会抛出异常,但后续操作可能抛出 -
避免复杂的线程所有权转移
// 保持线程所有权的清晰和简单
移动赋值运算符使得线程对象可以安全地在不同作用域和容器之间转移,同时保持资源的正确管理,这是现代 C++ 资源管理理念的重要体现。
C++11 std::thread::get_id() 函数
函数声明
cpp
std::thread::id get_id() const noexcept;
参数说明
- 无参数
返回值
- 返回
std::thread::id类型的对象,表示线程的唯一标识符 - 如果线程对象不关联任何线程(空线程),返回默认构造的
std::thread::id对象
作用
获取当前线程对象所管理线程的唯一标识符
详细使用示例
1. 基本用法
cpp
#include <iostream>
#include <thread>
#include <vector>
void worker(int id) {
std::cout << "Worker " << id << " has thread ID: "
<< std::this_thread::get_id() << std::endl;
}
int main() {
std::thread t1(worker, 1);
std::thread t2(worker, 2);
std::cout << "Main thread ID: " << std::this_thread::get_id() << std::endl;
std::cout << "t1 thread ID: " << t1.get_id() << std::endl;
std::cout << "t2 thread ID: " << t2.get_id() << std::endl;
t1.join();
t2.join();
return 0;
}
2. 空线程对象的 get_id()
cpp
#include <iostream>
#include <thread>
int main() {
// 默认构造的空线程对象
std::thread empty_thread;
// 获取空线程的ID
std::thread::id empty_id = empty_thread.get_id();
std::thread::id default_id; // 默认构造的thread::id
std::cout << "Empty thread ID: " << empty_id << std::endl;
std::cout << "Default ID: " << default_id << std::endl;
// 比较空线程ID和默认ID
if (empty_id == default_id) {
std::cout << "Empty thread has default (non-existent) ID" << std::endl;
}
// 检查线程是否有效
if (!empty_thread.joinable()) {
std::cout << "Empty thread is not joinable" << std::endl;
}
return 0;
}
运行结果:
Empty thread ID: thread::id of a non-executing thread
Default ID: thread::id of a non-executing thread
Empty thread has default (non-existent) ID
Empty thread is not joinable
3. 线程ID的比较和哈希
cpp
#include <iostream>
#include <thread>
#include <unordered_map>
#include <functional>
void task(const std::string& name) {
std::cout << "Task '" << name << "' running in thread: "
<< std::this_thread::get_id() << std::endl;
}
int main() {
std::unordered_map<std::thread::id, std::string> thread_map;
std::thread t1(task, "Task 1");
std::thread t2(task, "Task 2");
// 存储线程ID和对应的任务名称
thread_map[t1.get_id()] = "Task 1";
thread_map[t2.get_id()] = "Task 2";
thread_map[std::this_thread::get_id()] = "Main Thread";
// 输出所有线程信息
std::cout << "\nThread mapping:" << std::endl;
for (const auto& pair : thread_map) {
std::cout << "Thread ID: " << pair.first
<< " -> " << pair.second << std::endl;
}
// 线程ID比较
if (t1.get_id() != t2.get_id()) {
std::cout << "\nThread IDs are different" << std::endl;
}
// 哈希值演示
std::hash<std::thread::id> hasher;
std::cout << "Hash of t1 ID: " << hasher(t1.get_id()) << std::endl;
std::cout << "Hash of t2 ID: " << hasher(t2.get_id()) << std::endl;
t1.join();
t2.join();
return 0;
}
4. 实际应用:线程跟踪和调试
cpp
#include <iostream>
#include <thread>
#include <mutex>
#include <vector>
#include <sstream>
class ThreadLogger {
private:
std::mutex log_mutex;
public:
void log(const std::string& message) {
std::lock_guard<std::mutex> lock(log_mutex);
std::cout << "[Thread " << std::this_thread::get_id() << "] "
<< message << std::endl;
}
void log_creation(const std::string& thread_name) {
std::lock_guard<std::mutex> lock(log_mutex);
std::cout << "=== Created thread: " << thread_name
<< " with ID: " << std::this_thread::get_id() << " ===" << std::endl;
}
};
void worker_thread(ThreadLogger& logger, int id) {
logger.log_creation("Worker " + std::to_string(id));
for (int i = 0; i < 3; ++i) {
std::ostringstream oss;
oss << "Working... iteration " << i;
logger.log(oss.str());
std::this_thread::sleep_for(std::chrono::milliseconds(100));
}
logger.log("Finished work");
}
int main() {
ThreadLogger logger;
std::vector<std::thread> threads;
logger.log("Starting thread creation");
// 创建多个工作线程
for (int i = 0; i < 3; ++i) {
threads.emplace_back(worker_thread, std::ref(logger), i + 1);
}
// 主线程也记录一些信息
logger.log("Main thread waiting for workers to complete");
// 等待所有线程完成
for (auto& t : threads) {
t.join();
}
logger.log("All worker threads completed");
return 0;
}
5. 线程ID在性能分析中的应用
cpp
#include <iostream>
#include <thread>
#include <chrono>
#include <map>
#include <iomanip>
class PerformanceProfiler {
private:
std::mutex data_mutex;
std::map<std::thread::id, std::chrono::steady_clock::time_point> start_times;
std::map<std::thread::id, long long> thread_durations;
public:
void start_timing() {
std::lock_guard<std::mutex> lock(data_mutex);
start_times[std::this_thread::get_id()] = std::chrono::steady_clock::now();
}
void stop_timing() {
auto end_time = std::chrono::steady_clock::now();
std::lock_guard<std::mutex> lock(data_mutex);
auto start_time = start_times[std::this_thread::get_id()];
auto duration = std::chrono::duration_cast<std::chrono::microseconds>(
end_time - start_time);
thread_durations[std::this_thread::get_id()] = duration.count();
}
void print_report() {
std::lock_guard<std::mutex> lock(data_mutex);
std::cout << "\n=== Performance Report ===" << std::endl;
std::cout << std::setw(20) << "Thread ID"
<< std::setw(15) << "Duration (μs)" << std::endl;
std::cout << std::string(35, '-') << std::endl;
for (const auto& entry : thread_durations) {
std::cout << std::setw(20) << entry.first
<< std::setw(15) << entry.second << std::endl;
}
}
};
void intensive_task(PerformanceProfiler& profiler, int iterations) {
profiler.start_timing();
// 模拟一些工作
volatile long result = 0;
for (int i = 0; i < iterations; ++i) {
result += i * i;
}
std::this_thread::sleep_for(std::chrono::milliseconds(100));
profiler.stop_timing();
}
int main() {
PerformanceProfiler profiler;
std::vector<std::thread> threads;
// 创建不同工作负载的线程
threads.emplace_back(intensive_task, std::ref(profiler), 1000000);
threads.emplace_back(intensive_task, std::ref(profiler), 2000000);
threads.emplace_back(intensive_task, std::ref(profiler), 500000);
// 主线程也参与
intensive_task(profiler, 1500000);
// 等待所有线程完成
for (auto& t : threads) {
t.join();
}
// 打印性能报告
profiler.print_report();
return 0;
}
6. std::this_thread::get_id() 的使用
cpp
#include <iostream>
#include <thread>
#include <vector>
// 演示当前线程ID的获取
void demonstrate_this_thread_get_id() {
std::cout << "Current thread ID: " << std::this_thread::get_id() << std::endl;
}
class ThreadAwareObject {
private:
std::thread::id creation_thread_id;
public:
ThreadAwareObject() : creation_thread_id(std::this_thread::get_id()) {}
void check_thread_safety() {
std::thread::id current_thread_id = std::this_thread::get_id();
if (current_thread_id == creation_thread_id) {
std::cout << "Safe: Object used in creation thread" << std::endl;
} else {
std::cout << "Warning: Object used in different thread!" << std::endl;
std::cout << " Creation thread: " << creation_thread_id << std::endl;
std::cout << " Current thread: " << current_thread_id << std::endl;
}
}
};
int main() {
std::cout << "Main thread ID: " << std::this_thread::get_id() << std::endl;
// 在不同线程中获取当前线程ID
std::thread t1(demonstrate_this_thread_get_id);
std::thread t2(demonstrate_this_thread_get_id);
t1.join();
t2.join();
// 线程感知对象示例
ThreadAwareObject obj;
std::cout << "\nTesting thread-aware object:" << std::endl;
obj.check_thread_safety(); // 在主线程中使用
std::thread t3([&obj]() {
obj.check_thread_safety(); // 在子线程中使用
});
t3.join();
return 0;
}
重要注意事项和使用细节
1. 线程ID的生命周期
cpp
#include <iostream>
#include <thread>
void demonstrate_id_lifetime() {
std::thread::id thread_id;
{
std::thread temp_thread([](){
std::cout << "Temp thread ID: " << std::this_thread::get_id() << std::endl;
});
thread_id = temp_thread.get_id(); // 保存线程ID
temp_thread.join();
}
// 线程已结束,但ID仍然有效(可用于比较等操作)
std::cout << "Saved thread ID: " << thread_id << std::endl;
std::cout << "ID is still valid for comparison, but the thread no longer exists" << std::endl;
}
int main() {
demonstrate_id_lifetime();
return 0;
}
2. 线程ID的输出格式
cpp
#include <iostream>
#include <thread>
#include <sstream>
void demonstrate_id_format() {
std::thread t([](){});
std::thread::id id = t.get_id();
// 线程ID的输出格式是实现定义的
std::cout << "Thread ID as cout: " << id << std::endl;
// 转换为字符串
std::ostringstream oss;
oss << id;
std::string id_str = oss.str();
std::cout << "Thread ID as string: " << id_str << std::endl;
t.join();
// 空线程ID的输出
std::thread empty;
std::cout << "Empty thread ID: " << empty.get_id() << std::endl;
}
3. 线程ID在容器中的使用
cpp
#include <iostream>
#include <thread>
#include <set>
#include <vector>
#include <algorithm>
void demonstrate_id_in_containers() {
std::vector<std::thread> threads;
std::set<std::thread::id> thread_ids;
// 创建多个线程
for (int i = 0; i < 5; ++i) {
threads.emplace_back([](){
std::this_thread::sleep_for(std::chrono::milliseconds(10));
});
}
// 收集线程ID
for (auto& t : threads) {
thread_ids.insert(t.get_id());
}
// 添加主线程ID
thread_ids.insert(std::this_thread::get_id());
std::cout << "Unique thread IDs: " << thread_ids.size() << std::endl;
for (const auto& id : thread_ids) {
std::cout << " " << id << std::endl;
}
// 等待所有线程
for (auto& t : threads) {
t.join();
}
}
总结
get_id() 函数关键特性
| 特性 | 说明 |
|---|---|
| 函数声明 | std::thread::id get_id() const noexcept |
| 参数 | 无 |
| 返回值 | std::thread::id类型对象 |
| 异常安全 | noexcept(不会抛出异常) |
| 空线程返回值 | 默认构造的 std::thread::id |
std::thread::id 类型的特性
- 可比较性 :支持
==,!=,<,<=,>,>=操作 - 可哈希 :可用于
std::unordered_map和std::unordered_set - 可输出:支持流输出操作(输出格式实现定义)
- 默认构造:表示"非线程"的特殊值
- 拷贝安全:可安全拷贝和赋值
使用场景
- 调试和日志:跟踪哪个线程执行了特定操作
- 性能分析:关联性能数据与特定线程
- 线程管理:识别和管理特定线程
- 资源跟踪:将资源与创建线程关联
- 线程安全检查:验证操作是否在正确的线程执行
最佳实践
- 不要依赖ID的具体值,只用于比较和识别
- 线程结束后ID仍然有效,但对应的线程已不存在
- 空线程返回特殊的ID值,可用于检测线程有效性
- 结合RAII模式使用,确保线程资源正确管理
get_id()函数是多线程编程中重要的调试和管理工具,提供了识别和跟踪线程的标准方法。
C++11 std::thread::joinable() 函数
函数声明
cpp
bool joinable() const noexcept;
参数说明
- 无参数
返回值
- 返回
bool类型:true:线程对象关联着一个可执行线程false:线程对象不关联任何线程或线程不可加入
作用
检查线程对象是否关联着一个活动的、可加入(joinable)的线程
详细使用示例
1. 基本用法和状态检查
cpp
#include <iostream>
#include <thread>
#include <chrono>
void worker() {
std::cout << "Worker thread started" << std::endl;
std::this_thread::sleep_for(std::chrono::milliseconds(100));
std::cout << "Worker thread finished" << std::endl;
}
int main() {
// 情况1: 默认构造的空线程
std::thread t1;
std::cout << "Default constructed thread joinable: "
<< std::boolalpha << t1.joinable() << std::endl; // false
// 情况2: 关联线程的线程对象
std::thread t2(worker);
std::cout << "Thread with associated function joinable: "
<< t2.joinable() << std::endl; // true
// 情况3: 移动后的线程对象
std::thread t3 = std::move(t2);
std::cout << "After move - t2 joinable: " << t2.joinable() << std::endl; // false
std::cout << "After move - t3 joinable: " << t3.joinable() << std::endl; // true
if (t3.joinable()) {
t3.join();
}
// 情况4: join() 后的线程对象
std::cout << "After join - t3 joinable: " << t3.joinable() << std::endl; // false
return 0;
}
2. 安全的线程管理模式
cpp
#include <iostream>
#include <thread>
#include <stdexcept>
class SafeThreadManager {
public:
// 安全的join方法
static void safe_join(std::thread& t) {
if (t.joinable()) {
std::cout << "Joining thread..." << std::endl;
t.join();
std::cout << "Thread joined successfully" << std::endl;
} else {
std::cout << "Thread is not joinable, skipping join" << std::endl;
}
}
// 安全的detach方法
static void safe_detach(std::thread& t) {
if (t.joinable()) {
std::cout << "Detaching thread..." << std::endl;
t.detach();
std::cout << "Thread detached successfully" << std::endl;
} else {
std::cout << "Thread is not joinable, skipping detach" << std::endl;
}
}
};
void task() {
std::cout << "Task executing in thread: " << std::this_thread::get_id() << std::endl;
}
int main() {
// 测试各种情况下的安全操作
std::thread t1(task);
std::thread t2; // 空线程
// 安全操作示例
SafeThreadManager::safe_join(t1); // 正常join
SafeThreadManager::safe_join(t1); // 重复join(安全跳过)
SafeThreadManager::safe_join(t2); // 空线程(安全跳过)
std::thread t3(task);
SafeThreadManager::safe_detach(t3); // 正常detach
SafeThreadManager::safe_detach(t3); // 重复detach(安全跳过)
return 0;
}
3. RAII 线程包装器
cpp
#include <iostream>
#include <thread>
#include <vector>
#include <memory>
class ScopedThread {
private:
std::thread t;
public:
// 构造函数:接受线程对象
explicit ScopedThread(std::thread t_) : t(std::move(t_)) {
if (!t.joinable()) {
throw std::invalid_argument("Thread must be joinable");
}
}
// 移动构造
ScopedThread(ScopedThread&& other) noexcept : t(std::move(other.t)) {}
// 移动赋值
ScopedThread& operator=(ScopedThread&& other) noexcept {
if (this != &other) {
// 先安全地处理当前线程
safe_join();
t = std::move(other.t);
}
return *this;
}
// 禁止拷贝
ScopedThread(const ScopedThread&) = delete;
ScopedThread& operator=(const ScopedThread&) = delete;
// 析构函数:自动join
~ScopedThread() {
safe_join();
}
// 获取底层线程ID(用于调试)
std::thread::id get_id() const {
return t.get_id();
}
private:
void safe_join() {
if (t.joinable()) {
std::cout << "Auto-joining thread " << t.get_id() << std::endl;
t.join();
}
}
};
void worker(int id) {
std::cout << "Worker " << id << " starting..." << std::endl;
std::this_thread::sleep_for(std::chrono::milliseconds(100 * id));
std::cout << "Worker " << id << " finished" << std::endl;
}
int main() {
try {
std::vector<ScopedThread> threads;
// 创建多个受管线程
for (int i = 1; i <= 3; ++i) {
threads.emplace_back(std::thread(worker, i));
}
std::cout << "All threads created, they will auto-join when scope ends" << std::endl;
// 作用域结束时,所有线程自动join
} catch (const std::exception& e) {
std::cerr << "Error: " << e.what() << std::endl;
}
std::cout << "All threads completed successfully" << std::endl;
return 0;
}
4. 线程池中的 joinable() 检查
cpp
#include <iostream>
#include <thread>
#include <vector>
#include <queue>
#include <mutex>
#include <condition_variable>
#include <functional>
#include <atomic>
class ThreadPool {
private:
std::vector<std::thread> workers;
std::queue<std::function<void()>> tasks;
std::mutex queue_mutex;
std::condition_variable condition;
std::atomic<bool> stop;
public:
ThreadPool(size_t threads) : stop(false) {
for (size_t i = 0; i < threads; ++i) {
workers.emplace_back([this] {
while (true) {
std::function<void()> task;
{
std::unique_lock<std::mutex> lock(queue_mutex);
condition.wait(lock, [this] {
return stop || !tasks.empty();
});
if (stop && tasks.empty()) {
return;
}
task = std::move(tasks.front());
tasks.pop();
}
task();
}
});
}
}
// 检查所有工作线程是否活跃
bool all_threads_joinable() const {
for (const auto& worker : workers) {
if (!worker.joinable()) {
return false;
}
}
return true;
}
// 添加任务
template<class F>
void enqueue(F&& f) {
{
std::unique_lock<std::mutex> lock(queue_mutex);
tasks.emplace(std::forward<F>(f));
}
condition.notify_one();
}
// 安全停止线程池
~ThreadPool() {
{
std::unique_lock<std::mutex> lock(queue_mutex);
stop = true;
}
condition.notify_all();
// 只join可join的线程
for (std::thread& worker : workers) {
if (worker.joinable()) {
worker.join();
}
}
}
};
int main() {
ThreadPool pool(4);
// 验证线程池状态
std::cout << "All threads joinable: " << pool.all_threads_joinable() << std::endl;
// 添加一些任务
for (int i = 0; i < 8; ++i) {
pool.enqueue([i] {
std::cout << "Task " << i << " executed by thread "
<< std::this_thread::get_id() << std::endl;
std::this_thread::sleep_for(std::chrono::milliseconds(100));
});
}
std::this_thread::sleep_for(std::chrono::seconds(1));
std::cout << "Thread pool shutting down..." << std::endl;
return 0;
}
5. 异常安全的线程处理
cpp
#include <iostream>
#include <thread>
#include <stdexcept>
#include <memory>
// 异常安全的线程包装器
class ExceptionSafeThread {
private:
std::thread t;
std::string name;
public:
ExceptionSafeThread(std::thread thread, const std::string& thread_name)
: t(std::move(thread)), name(thread_name) {}
// 移动构造
ExceptionSafeThread(ExceptionSafeThread&& other) noexcept
: t(std::move(other.t)), name(std::move(other.name)) {}
// 移动赋值
ExceptionSafeThread& operator=(ExceptionSafeThread&& other) noexcept {
if (this != &other) {
safe_cleanup();
t = std::move(other.t);
name = std::move(other.name);
}
return *this;
}
// 禁止拷贝
ExceptionSafeThread(const ExceptionSafeThread&) = delete;
ExceptionSafeThread& operator=(const ExceptionSafeThread&) = delete;
~ExceptionSafeThread() {
safe_cleanup();
}
// 等待线程完成(带超时检查)
bool join_with_timeout(std::chrono::milliseconds timeout) {
if (!t.joinable()) {
std::cout << name << ": Thread is not joinable" << std::endl;
return true;
}
auto start = std::chrono::steady_clock::now();
while (t.joinable()) {
if (std::chrono::steady_clock::now() - start > timeout) {
std::cout << name << ": Join timeout reached, detaching thread" << std::endl;
t.detach();
return false;
}
std::this_thread::sleep_for(std::chrono::milliseconds(10));
}
return true;
}
// 强制分离线程
void detach_if_joinable() {
if (t.joinable()) {
std::cout << name << ": Detaching thread" << std::endl;
t.detach();
}
}
// 检查线程状态
void print_status() const {
std::cout << name << ": joinable = " << std::boolalpha << t.joinable();
if (t.joinable()) {
std::cout << ", thread_id = " << t.get_id();
}
std::cout << std::endl;
}
private:
void safe_cleanup() {
if (t.joinable()) {
std::cout << name << ": WARNING - Thread was not properly joined, detaching" << std::endl;
t.detach();
}
}
};
void risky_operation(bool should_throw) {
std::cout << "Risky operation started" << std::endl;
std::this_thread::sleep_for(std::chrono::milliseconds(200));
if (should_throw) {
throw std::runtime_error("Simulated error in thread");
}
std::cout << "Risky operation completed successfully" << std::endl;
}
int main() {
try {
// 创建受管线程
ExceptionSafeThread safe_thread(
std::thread([] {
std::this_thread::sleep_for(std::chrono::milliseconds(500));
std::cout << "Background task completed" << std::endl;
}),
"BackgroundWorker"
);
safe_thread.print_status();
// 模拟可能抛出异常的操作
risky_operation(false);
// 尝试正常join(带超时)
if (!safe_thread.join_with_timeout(std::chrono::milliseconds(1000))) {
std::cout << "Thread was detached due to timeout" << std::endl;
}
safe_thread.print_status();
} catch (const std::exception& e) {
std::cerr << "Exception caught: " << e.what() << std::endl;
}
return 0;
}
joinable() 返回 false 的情况详解
1. 默认构造的线程对象
cpp
std::thread t; // 默认构造
std::cout << "Default constructed: " << t.joinable() << std::endl; // false
2. 被移动的线程对象
cpp
std::thread t1([]{});
std::thread t2 = std::move(t1); // 移动构造
std::cout << "After move - t1: " << t1.joinable() << std::endl; // false
std::cout << "After move - t2: " << t2.joinable() << std::endl; // true
3. 调用 join() 后的线程对象
cpp
std::thread t([]{});
t.join();
std::cout << "After join: " << t.joinable() << std::endl; // false
4. 调用 detach() 后的线程对象
cpp
std::thread t([]{});
t.detach();
std::cout << "After detach: " << t.joinable() << std::endl; // false
5. 综合测试
cpp
#include <iostream>
#include <thread>
void test_joinable_states() {
std::thread t1; // 情况1: 默认构造
std::cout << "Case 1 - Default constructed: " << t1.joinable() << std::endl;
std::thread t2([]{
std::this_thread::sleep_for(std::chrono::milliseconds(50));
}); // 情况2: 正常线程
std::cout << "Case 2 - With function: " << t2.joinable() << std::endl;
std::thread t3 = std::move(t2); // 情况3: 移动后
std::cout << "Case 3 - After move (source): " << t2.joinable() << std::endl;
std::cout << "Case 3 - After move (target): " << t3.joinable() << std::endl;
t3.join(); // 情况4: join后
std::cout << "Case 4 - After join: " << t3.joinable() << std::endl;
std::thread t4([]{});
t4.detach(); // 情况5: detach后
std::cout << "Case 5 - After detach: " << t4.joinable() << std::endl;
}
int main() {
test_joinable_states();
return 0;
}
重要注意事项和使用细节
1. 必须检查 joinable() 再调用 join() 或 detach()
cpp
std::thread t([]{});
// 错误:可能抛出 std::system_error
// t.join(); // 如果线程已经结束或不可join,会抛出异常
// 正确:先检查
if (t.joinable()) {
t.join(); // 安全
}
2. 析构函数的安全性
cpp
class ThreadHolder {
std::thread t;
public:
ThreadHolder(std::thread thread) : t(std::move(thread)) {}
~ThreadHolder() {
// 必须检查,否则可能终止程序
if (t.joinable()) {
std::cout << "WARNING: Thread not joined, detaching..." << std::endl;
t.detach(); // 或者终止程序,根据需求决定
}
}
};
3. 移动语义的特殊情况
cpp
std::thread create_thread() {
return std::thread([]{
std::cout << "Temporary thread" << std::endl;
});
}
int main() {
auto t = create_thread(); // 返回值优化,线程仍然joinable
std::cout << "Returned thread joinable: " << t.joinable() << std::endl; // true
if (t.joinable()) {
t.join();
}
return 0;
}
总结
joinable() 函数关键特性
| 特性 | 说明 |
|---|---|
| 函数声明 | bool joinable() const noexcept |
| 参数 | 无 |
| 返回值 | true(可加入)/false(不可加入) |
| 异常安全 | noexcept(不会抛出异常) |
joinable() 返回 false 的情况
- 默认构造的线程对象
- 被移动后的源线程对象
- 调用 join() 后的线程对象
- 调用 detach() 后的线程对象
最佳实践
-
总是先检查 joinable()
cppif (t.joinable()) { t.join(); // 或 t.detach(); } -
在析构函数中正确处理线程
cpp~MyClass() { if (worker_thread.joinable()) { // 根据需求选择 join() 或 detach() worker_thread.join(); // 或 detach() } } -
使用 RAII 包装器
// 使用 ScopedThread 等包装器自动管理生命周期 -
避免重复操作
cpp// 错误:可能重复join // t.join(); t.join(); // 正确 if (t.joinable()) t.join(); if (t.joinable()) t.join(); // 第二次不会执行
joinable()函数是多线程编程中的安全检查工具,正确使用可以避免程序崩溃和资源泄漏,是编写健壮多线程代码的基础。
C++11 std::thread::join() 函数
函数声明
cpp
void join();
参数说明
- 无参数
返回值
- 无返回值(void)
作用
阻塞当前线程,直到被调用的线程对象执行完成
详细使用示例
1. 基本用法和线程同步
cpp
#include <iostream>
#include <thread>
#include <chrono>
void worker(int id) {
std::cout << "Worker " << id << " started in thread: "
<< std::this_thread::get_id() << std::endl;
// 模拟工作负载
for (int i = 0; i < 3; ++i) {
std::cout << "Worker " << id << " working... (" << (i+1) << "/3)" << std::endl;
std::this_thread::sleep_for(std::chrono::milliseconds(100));
}
std::cout << "Worker " << id << " completed" << std::endl;
}
int main() {
std::cout << "Main thread started: " << std::this_thread::get_id() << std::endl;
// 创建并启动工作线程
std::thread t1(worker, 1);
std::thread t2(worker, 2);
std::cout << "Main thread waiting for workers to complete..." << std::endl;
// 等待线程完成 - 主线程在此阻塞
t1.join(); // 等待t1完成
std::cout << "Worker 1 joined" << std::endl;
t2.join(); // 等待t2完成
std::cout << "Worker 2 joined" << std::endl;
std::cout << "All workers completed, main thread continuing..." << std::endl;
return 0;
}
2. 顺序执行控制
cpp
#include <iostream>
#include <thread>
#include <chrono>
void stage1() {
std::cout << "=== Stage 1: Data preparation ===" << std::endl;
std::this_thread::sleep_for(std::chrono::milliseconds(200));
std::cout << "Stage 1 completed" << std::endl;
}
void stage2() {
std::cout << "=== Stage 2: Data processing ===" << std::endl;
std::this_thread::sleep_for(std::chrono::milliseconds(300));
std::cout << "Stage 2 completed" << std::endl;
}
void stage3() {
std::cout << "=== Stage 3: Results analysis ===" << std::endl;
std::this_thread::sleep_for(std::chrono::milliseconds(250));
std::cout << "Stage 3 completed" << std::endl;
}
int main() {
// 顺序执行:每个阶段必须在前一个阶段完成后开始
std::cout << "Starting sequential pipeline..." << std::endl;
std::thread t1(stage1);
t1.join(); // 等待阶段1完成
std::thread t2(stage2);
t2.join(); // 等待阶段2完成
std::thread t3(stage3);
t3.join(); // 等待阶段3完成
std::cout << "Pipeline completed successfully!" << std::endl;
return 0;
}
3. 并行执行与结果收集
cpp
#include <iostream>
#include <thread>
#include <vector>
#include <numeric>
#include <random>
class ParallelCalculator {
private:
std::vector<int> data;
public:
ParallelCalculator(size_t size) {
// 生成测试数据
std::random_device rd;
std::mt19937 gen(rd());
std::uniform_int_distribution<> dis(1, 100);
data.resize(size);
for (auto& val : data) {
val = dis(gen);
}
}
// 并行计算总和
long long parallel_sum(size_t num_threads) {
std::vector<std::thread> threads;
std::vector<long long> partial_sums(num_threads, 0);
size_t chunk_size = data.size() / num_threads;
// 启动工作线程
for (size_t i = 0; i < num_threads; ++i) {
size_t start = i * chunk_size;
size_t end = (i == num_threads - 1) ? data.size() : (i + 1) * chunk_size;
threads.emplace_back([this, start, end, i, &partial_sums]() {
long long sum = 0;
for (size_t j = start; j < end; ++j) {
sum += data[j];
}
partial_sums[i] = sum;
std::cout << "Thread " << i << " calculated sum: " << sum << std::endl;
});
}
// 等待所有线程完成
std::cout << "Waiting for all calculation threads to complete..." << std::endl;
for (auto& t : threads) {
t.join();
}
// 汇总结果
long long total = std::accumulate(partial_sums.begin(), partial_sums.end(), 0LL);
return total;
}
// 验证结果(单线程计算)
long long sequential_sum() const {
return std::accumulate(data.begin(), data.end(), 0LL);
}
};
int main() {
const size_t data_size = 1000000;
const size_t num_threads = 4;
ParallelCalculator calc(data_size);
auto start = std::chrono::high_resolution_clock::now();
long long parallel_result = calc.parallel_sum(num_threads);
auto end = std::chrono::high_resolution_clock::now();
auto parallel_time = std::chrono::duration_cast<std::chrono::microseconds>(end - start);
start = std::chrono::high_resolution_clock::now();
long long sequential_result = calc.sequential_sum();
end = std::chrono::high_resolution_clock::now();
auto sequential_time = std::chrono::duration_cast<std::chrono::microseconds>(end - start);
std::cout << "\nResults:" << std::endl;
std::cout << "Parallel sum: " << parallel_result
<< " (time: " << parallel_time.count() << " μs)" << std::endl;
std::cout << "Sequential sum: " << sequential_result
<< " (time: " << sequential_time.count() << " μs)" << std::endl;
std::cout << "Results match: " << std::boolalpha
<< (parallel_result == sequential_result) << std::endl;
return 0;
}
4. 异常安全的 join() 使用
cpp
#include <iostream>
#include <thread>
#include <stdexcept>
#include <vector>
class SafeThreadManager {
public:
// 安全的join函数,处理各种边界情况
static void safe_join(std::thread& t) {
if (!t.joinable()) {
std::cout << "Thread is not joinable, skipping join" << std::endl;
return;
}
try {
std::cout << "Joining thread " << t.get_id() << "..." << std::endl;
t.join();
std::cout << "Thread " << t.get_id() << " joined successfully" << std::endl;
} catch (const std::system_error& e) {
std::cerr << "System error while joining thread: " << e.what() << std::endl;
} catch (const std::exception& e) {
std::cerr << "Error joining thread: " << e.what() << std::endl;
}
}
// 带超时的join(模拟)
static bool join_with_timeout(std::thread& t, int max_wait_seconds) {
if (!t.joinable()) {
return true; // 线程已经结束
}
std::cout << "Waiting for thread " << t.get_id()
<< " (timeout: " << max_wait_seconds << "s)..." << std::endl;
for (int i = 0; i < max_wait_seconds; ++i) {
if (!t.joinable()) {
std::cout << "Thread completed within timeout" << std::endl;
return true;
}
std::this_thread::sleep_for(std::chrono::seconds(1));
std::cout << "Waited " << (i + 1) << " second(s)..." << std::endl;
}
if (t.joinable()) {
std::cout << "Timeout reached, thread still running" << std::endl;
return false;
}
return true;
}
};
void normal_worker() {
std::cout << "Normal worker started" << std::endl;
std::this_thread::sleep_for(std::chrono::seconds(2));
std::cout << "Normal worker completed" << std::endl;
}
void long_running_worker() {
std::cout << "Long-running worker started" << std::endl;
std::this_thread::sleep_for(std::chrono::seconds(5));
std::cout << "Long-running worker completed" << std::endl;
}
int main() {
// 测试正常join
std::thread t1(normal_worker);
SafeThreadManager::safe_join(t1);
// 测试重复join
std::cout << "\nTesting duplicate join:" << std::endl;
SafeThreadManager::safe_join(t1); // 应该输出"not joinable"
// 测试带超时的join
std::cout << "\nTesting join with timeout:" << std::endl;
std::thread t2(long_running_worker);
bool completed = SafeThreadManager::join_with_timeout(t2, 3); // 3秒超时
if (!completed && t2.joinable()) {
std::cout << "Thread did not complete in time, detaching..." << std::endl;
t2.detach();
} else {
SafeThreadManager::safe_join(t2);
}
return 0;
}
5. RAII 线程管理类
cpp
#include <iostream>
#include <thread>
#include <vector>
#include <memory>
class JoinedThread {
private:
std::thread t;
public:
// 构造函数:立即启动线程
template<typename Function, typename... Args>
explicit JoinedThread(Function&& f, Args&&... args)
: t(std::forward<Function>(f), std::forward<Args>(args)...) {}
// 移动构造
JoinedThread(JoinedThread&& other) noexcept : t(std::move(other.t)) {}
// 移动赋值
JoinedThread& operator=(JoinedThread&& other) noexcept {
if (this != &other) {
// 等待当前线程完成(如果有)
if (t.joinable()) {
t.join();
}
t = std::move(other.t);
}
return *this;
}
// 禁止拷贝
JoinedThread(const JoinedThread&) = delete;
JoinedThread& operator=(const JoinedThread&) = delete;
// 析构函数:自动join
~JoinedThread() {
if (t.joinable()) {
std::cout << "Auto-joining thread " << t.get_id() << " in destructor" << std::endl;
t.join();
}
}
// 显式等待完成
void wait() {
if (t.joinable()) {
t.join();
}
}
// 获取线程ID
std::thread::id get_id() const {
return t.get_id();
}
// 检查是否已完成
bool joinable() const {
return t.joinable();
}
};
void worker_task(int id, int duration_seconds) {
std::cout << "Task " << id << " started in thread "
<< std::this_thread::get_id() << std::endl;
std::this_thread::sleep_for(std::chrono::seconds(duration_seconds));
std::cout << "Task " << id << " completed" << std::endl;
}
int main() {
std::cout << "=== RAII Thread Management Demo ===" << std::endl;
{
// 使用RAII管理线程
JoinedThread t1(worker_task, 1, 2);
JoinedThread t2(worker_task, 2, 1);
std::cout << "Thread 1 ID: " << t1.get_id() << std::endl;
std::cout << "Thread 2 ID: " << t2.get_id() << std::endl;
// 线程会在作用域结束时自动join
std::cout << "Leaving scope, threads will auto-join..." << std::endl;
}
std::cout << "All threads completed automatically" << std::endl;
return 0;
}
join() 的错误用法和陷阱
1. 对不可join的线程调用join()
cpp
#include <iostream>
#include <thread>
#include <system_error>
void demonstrate_join_errors() {
std::thread t1; // 默认构造,不可join
try {
t1.join(); // 错误:对不可join的线程调用join
} catch (const std::system_error& e) {
std::cerr << "Error joining default-constructed thread: " << e.what() << std::endl;
}
std::thread t2([]{
std::cout << "Worker thread" << std::endl;
});
t2.join(); // 正确
try {
t2.join(); // 错误:重复join
} catch (const std::system_error& e) {
std::cerr << "Error joining already-joined thread: " << e.what() << std::endl;
}
std::thread t3([]{});
t3.detach(); // 分离线程
try {
t3.join(); // 错误:对已detach的线程调用join
} catch (const std::system_error& e) {
std::cerr << "Error joining detached thread: " << e.what() << std::endl;
}
}
int main() {
demonstrate_join_errors();
return 0;
}
2. 死锁场景
cpp
#include <iostream>
#include <thread>
#include <mutex>
std::mutex mtx1, mtx2;
void worker1() {
std::lock_guard<std::mutex> lock1(mtx1);
std::cout << "Worker 1 acquired mutex 1" << std::endl;
std::this_thread::sleep_for(std::chrono::milliseconds(100));
std::lock_guard<std::mutex> lock2(mtx2); // 可能死锁
std::cout << "Worker 1 acquired mutex 2" << std::endl;
}
void worker2() {
std::lock_guard<std::mutex> lock2(mtx2);
std::cout << "Worker 2 acquired mutex 2" << std::endl;
std::this_thread::sleep_for(std::chrono::milliseconds(100));
std::lock_guard<std::mutex> lock1(mtx1); // 可能死锁
std::cout << "Worker 2 acquired mutex 1" << std::endl;
}
void demonstrate_deadlock() {
std::thread t1(worker1);
std::thread t2(worker2);
std::cout << "Main thread waiting for workers..." << std::endl;
// 如果发生死锁,join会永远阻塞
auto start = std::chrono::steady_clock::now();
t1.join();
auto mid = std::chrono::steady_clock::now();
t2.join();
auto end = std::chrono::steady_clock::now();
auto duration1 = std::chrono::duration_cast<std::chrono::milliseconds>(mid - start);
auto duration2 = std::chrono::duration_cast<std::chrono::milliseconds>(end - mid);
std::cout << "Thread 1 joined after " << duration1.count() << "ms" << std::endl;
std::cout << "Thread 2 joined after " << duration2.count() << "ms" << std::endl;
}
int main() {
demonstrate_deadlock();
return 0;
}
重要注意事项和使用细节
1. join() 的阻塞特性
cpp
#include <iostream>
#include <thread>
#include <chrono>
void demonstrate_blocking() {
auto start = std::chrono::steady_clock::now();
std::thread t([]() {
std::this_thread::sleep_for(std::chrono::seconds(2));
std::cout << "Worker thread completed" << std::endl;
});
auto after_creation = std::chrono::steady_clock::now();
std::cout << "Thread created after "
<< std::chrono::duration_cast<std::chrono::milliseconds>(
after_creation - start).count() << "ms" << std::endl;
// join() 会阻塞直到线程完成
t.join();
auto after_join = std::chrono::steady_clock::now();
std::cout << "Thread joined after "
<< std::chrono::duration_cast<std::chrono::milliseconds>(
after_join - start).count() << "ms" << std::endl;
}
int main() {
demonstrate_blocking();
return 0;
}
2. join() 与异常安全
cpp
#include <iostream>
#include <thread>
#include <stdexcept>
class ExceptionSafeJoin {
private:
std::thread t;
public:
ExceptionSafeJoin(std::thread thread) : t(std::move(thread)) {
if (!t.joinable()) {
throw std::invalid_argument("Thread must be joinable");
}
}
~ExceptionSafeJoin() {
if (t.joinable()) {
try {
std::cout << "Safely joining thread in destructor..." << std::endl;
t.join();
} catch (const std::exception& e) {
std::cerr << "Error during safe join: " << e.what() << std::endl;
}
}
}
// 禁止拷贝
ExceptionSafeJoin(const ExceptionSafeJoin&) = delete;
ExceptionSafeJoin& operator=(const ExceptionSafeJoin&) = delete;
// 允许移动
ExceptionSafeJoin(ExceptionSafeJoin&&) = default;
ExceptionSafeJoin& operator=(ExceptionSafeJoin&&) = default;
};
void risky_operation() {
throw std::runtime_error("Something went wrong!");
}
int main() {
try {
ExceptionSafeJoin safe_thread(std::thread([]() {
std::this_thread::sleep_for(std::chrono::seconds(1));
std::cout << "Background task completed" << std::endl;
}));
risky_operation(); // 抛出异常
} catch (const std::exception& e) {
std::cout << "Caught exception: " << e.what() << std::endl;
// safe_thread 的析构函数会自动join,确保线程不会泄漏
}
return 0;
}
总结
join() 函数关键特性
| 特性 | 说明 |
|---|---|
| 函数声明 | void join() |
| 参数 | 无 |
| 返回值 | 无 |
| 异常 | 可能抛出 std::system_error |
join() 的有效调用条件
- 线程对象关联着活动线程 (
joinable() == true) - 线程尚未被 join 过
- 线程尚未被 detach
常见错误场景
| 错误场景 | 结果 |
|---|---|
| 对默认构造的线程调用 join() | std::system_error |
| 重复调用 join() | std::system_error |
| 对已 detach 的线程调用 join() | std::system_error |
| 线程自身调用自己的 join() | 死锁 |
最佳实践
-
总是先检查 joinable()
cppif (t.joinable()) { t.join(); } -
使用 RAII 模式管理线程生命周期
cppclass ScopedThread { std::thread t; public: ~ScopedThread() { if (t.joinable()) t.join(); } // ... 其他成员函数 }; -
异常安全设计
cppvoid safe_function() { std::thread t(worker); ExceptionGuard guard(t); // 确保异常时线程被正确join // 可能抛出异常的操作 } -
避免 join() 的阻塞导致界面冻结
// 在GUI应用中,考虑使用异步操作代替直接join
join()是多线程编程中的基本同步机制,正确使用可以确保线程间的有序执行和资源的安全释放。
C++11 std::thread::detach() 函数详解
函数声明
cpp
void detach();
参数说明
- 无参数
返回值
- 无返回值(void)
作用
将线程对象与底层执行线程分离,允许线程独立运行。分离后,线程资源在线程结束时由系统自动回收。
详细使用示例
1. 基本用法和分离线程行为
cpp
#include <iostream>
#include <thread>
#include <chrono>
void background_worker() {
std::cout << "Background worker started in thread: "
<< std::this_thread::get_id() << std::endl;
// 模拟长时间运行的后台任务
for (int i = 1; i <= 5; ++i) {
std::cout << "Background working... (" << i << "/5)" << std::endl;
std::this_thread::sleep_for(std::chrono::milliseconds(200));
}
std::cout << "Background worker completed" << std::endl;
}
int main() {
std::cout << "Main thread started: " << std::this_thread::get_id() << std::endl;
// 创建后台工作线程
std::thread t(background_worker);
std::cout << "Worker thread ID: " << t.get_id() << std::endl;
std::cout << "Thread joinable before detach: " << t.joinable() << std::endl;
// 分离线程 - 线程现在独立运行
t.detach();
std::cout << "Thread joinable after detach: " << t.joinable() << std::endl;
std::cout << "Main thread continuing immediately..." << std::endl;
// 主线程继续执行其他工作
for (int i = 0; i < 3; ++i) {
std::cout << "Main thread working... (" << (i+1) << "/3)" << std::endl;
std::this_thread::sleep_for(std::chrono::milliseconds(300));
}
std::cout << "Main thread completed" << std::endl;
std::cout << "Note: Background thread may still be running" << std::endl;
return 0;
}
2. 守护线程(Daemon Thread)模式
cpp
#include <iostream>
#include <thread>
#include <chrono>
#include <atomic>
#include <vector>
class DaemonService {
private:
std::atomic<bool> running_{false};
std::thread worker_thread_;
public:
void start() {
if (running_) {
std::cout << "Service already running" << std::endl;
return;
}
running_ = true;
worker_thread_ = std::thread(&DaemonService::worker_loop, this);
// 分离线程,使其成为守护线程
worker_thread_.detach();
std::cout << "Daemon service started" << std::endl;
}
void stop() {
running_ = false;
std::cout << "Daemon service stopping..." << std::endl;
}
bool is_running() const {
return running_;
}
private:
void worker_loop() {
std::cout << "Daemon worker started in thread: "
<< std::this_thread::get_id() << std::endl;
int iteration = 0;
while (running_) {
// 模拟守护任务
std::cout << "Daemon iteration: " << ++iteration << std::endl;
std::this_thread::sleep_for(std::chrono::seconds(1));
// 安全检查:避免无限循环
if (iteration > 10) {
std::cout << "Daemon safety limit reached, stopping" << std::endl;
running_ = false;
}
}
std::cout << "Daemon worker stopped" << std::endl;
}
};
int main() {
DaemonService service;
std::cout << "Starting daemon service..." << std::endl;
service.start();
// 主线程继续工作
for (int i = 0; i < 5; ++i) {
std::cout << "Main thread working... (" << (i+1) << "/5)" << std::endl;
std::this_thread::sleep_for(std::chrono::milliseconds(800));
}
std::cout << "Stopping daemon service..." << std::endl;
service.stop();
// 给守护线程一些时间来完成
std::this_thread::sleep_for(std::chrono::seconds(2));
std::cout << "Main thread completed" << std::endl;
return 0;
}
3. 日志记录器的分离线程实现
cpp
#include <iostream>
#include <thread>
#include <queue>
#include <mutex>
#include <condition_variable>
#include <atomic>
#include <sstream>
#include <fstream>
class AsyncLogger {
private:
std::queue<std::string> log_queue_;
std::mutex queue_mutex_;
std::condition_variable queue_cv_;
std::atomic<bool> running_{false};
std::thread worker_thread_;
std::ofstream log_file_;
public:
AsyncLogger(const std::string& filename) {
log_file_.open(filename, std::ios::app);
if (!log_file_.is_open()) {
throw std::runtime_error("Cannot open log file");
}
running_ = true;
worker_thread_ = std::thread(&AsyncLogger::log_worker, this);
worker_thread_.detach(); // 分离日志工作线程
}
~AsyncLogger() {
stop();
}
void log(const std::string& message) {
{
std::lock_guard<std::mutex> lock(queue_mutex_);
std::ostringstream oss;
oss << "[" << std::this_thread::get_id() << "] " << message;
log_queue_.push(oss.str());
}
queue_cv_.notify_one();
}
void stop() {
if (running_.exchange(false)) {
queue_cv_.notify_all();
// 注意:线程已分离,我们无法join,但可以等待一小段时间
std::this_thread::sleep_for(std::chrono::milliseconds(100));
}
if (log_file_.is_open()) {
log_file_.close();
}
}
private:
void log_worker() {
std::cout << "Log worker started in thread: "
<< std::this_thread::get_id() << std::endl;
while (running_ || !log_queue_.empty()) {
std::unique_lock<std::mutex> lock(queue_mutex_);
// 等待日志消息或停止信号
queue_cv_.wait(lock, [this]() {
return !log_queue_.empty() || !running_;
});
// 处理所有待处理的日志消息
while (!log_queue_.empty()) {
auto message = log_queue_.front();
log_queue_.pop();
lock.unlock(); // 释放锁,允许新消息入队
// 写入文件(和标准输出用于演示)
log_file_ << message << std::endl;
std::cout << "LOG: " << message << std::endl;
lock.lock(); // 重新获取锁以检查队列
}
}
std::cout << "Log worker stopped" << std::endl;
}
};
int main() {
try {
AsyncLogger logger("demo.log");
// 模拟多线程日志记录
std::vector<std::thread> threads;
for (int i = 0; i < 3; ++i) {
threads.emplace_back([i, &logger]() {
for (int j = 0; j < 5; ++j) {
logger.log("Thread " + std::to_string(i) +
" - Message " + std::to_string(j));
std::this_thread::sleep_for(std::chrono::milliseconds(100));
}
});
}
// 主线程也记录一些消息
for (int i = 0; i < 3; ++i) {
logger.log("Main thread - Message " + std::to_string(i));
std::this_thread::sleep_for(std::chrono::milliseconds(150));
}
// 等待所有工作线程完成
for (auto& t : threads) {
t.join();
}
std::cout << "All threads completed, logger will be destroyed" << std::endl;
} catch (const std::exception& e) {
std::cerr << "Error: " << e.what() << std::endl;
}
return 0;
}
4. 分离线程的资源管理挑战
cpp
#include <iostream>
#include <thread>
#include <memory>
#include <vector>
class ResourceUser {
private:
std::vector<int> data_;
public:
ResourceUser(size_t size) : data_(size, 42) {
std::cout << "ResourceUser constructed with " << size << " elements" << std::endl;
}
~ResourceUser() {
std::cout << "ResourceUser destroyed" << std::endl;
}
void process() {
std::cout << "Processing data in thread: " << std::this_thread::get_id() << std::endl;
std::this_thread::sleep_for(std::chrono::milliseconds(500));
std::cout << "Processing completed" << std::endl;
}
};
void demonstrate_lifetime_issue() {
std::cout << "=== Demonstrating Lifetime Issue ===" << std::endl;
// 危险:局部对象可能在分离线程完成前被销毁
ResourceUser local_resource(1000);
std::thread t([&local_resource]() {
std::cout << "Thread started, will process resource..." << std::endl;
std::this_thread::sleep_for(std::chrono::milliseconds(100));
local_resource.process(); // 可能访问已销毁的对象!
});
t.detach(); // 线程继续运行,但local_resource可能很快被销毁
std::cout << "Function ending, local_resource will be destroyed soon!" << std::endl;
}
void demonstrate_safe_approach() {
std::cout << "\n=== Demonstrating Safe Approach ===" << std::endl;
// 安全:使用shared_ptr确保资源生命周期
auto shared_resource = std::make_shared<ResourceUser>(1000);
std::thread t([shared_resource]() { // 拷贝shared_ptr,延长生命周期
std::cout << "Thread started, will process resource..." << std::endl;
std::this_thread::sleep_for(std::chrono::milliseconds(100));
shared_resource->process(); // 安全:资源由shared_ptr管理
});
t.detach();
std::cout << "Function ending, but resource is safe due to shared_ptr" << std::endl;
}
int main() {
demonstrate_lifetime_issue();
// 给第一个演示的线程一些时间(但可能已经太迟)
std::this_thread::sleep_for(std::chrono::milliseconds(50));
demonstrate_safe_approach();
// 等待足够时间让所有线程完成
std::this_thread::sleep_for(std::chrono::seconds(1));
return 0;
}
5. 监控和通信模式
cpp
#include <iostream>
#include <thread>
#include <atomic>
#include <chrono>
#include <future>
class MonitoredDetachedThread {
private:
std::atomic<bool> completed_{false};
std::atomic<bool> failed_{false};
std::promise<void> completion_signal_;
public:
// 启动受监控的分离线程
std::future<void> start_detached_task() {
auto future = completion_signal_.get_future();
std::thread t([this]() {
try {
std::cout << "Monitored task started in thread: "
<< std::this_thread::get_id() << std::endl;
// 模拟工作(可能成功或失败)
for (int i = 0; i < 3; ++i) {
std::cout << "Working... (" << (i+1) << "/3)" << std::endl;
std::this_thread::sleep_for(std::chrono::milliseconds(200));
// 模拟可能的失败
if (i == 1) {
// 取消注释下面一行来测试失败情况
// throw std::runtime_error("Simulated failure");
}
}
completed_ = true;
std::cout << "Task completed successfully" << std::endl;
completion_signal_.set_value();
} catch (const std::exception& e) {
failed_ = true;
std::cerr << "Task failed: " << e.what() << std::endl;
completion_signal_.set_exception(std::current_exception());
}
});
t.detach();
return future;
}
bool is_completed() const { return completed_; }
bool has_failed() const { return failed_; }
};
int main() {
MonitoredDetachedThread monitored_task;
std::cout << "Starting monitored detached task..." << std::endl;
auto future = monitored_task.start_detached_task();
// 主线程可以继续工作,同时监控分离的线程
std::cout << "Main thread continuing work..." << std::endl;
try {
// 等待任务完成(带超时)
auto status = future.wait_for(std::chrono::seconds(2));
if (status == std::future_status::ready) {
future.get(); // 获取结果(或异常)
std::cout << "Task completed within timeout" << std::endl;
} else {
std::cout << "Task still running after timeout" << std::endl;
}
} catch (const std::exception& e) {
std::cerr << "Caught exception from task: " << e.what() << std::endl;
}
std::cout << "Final status - Completed: " << monitored_task.is_completed()
<< ", Failed: " << monitored_task.has_failed() << std::endl;
return 0;
}
detach() 的错误用法和陷阱
1. 访问已销毁的局部变量
cpp
#include <iostream>
#include <thread>
#include <string>
void dangerous_detach() {
std::string local_data = "Important data";
std::thread t([&local_data]() { // 危险:捕获局部变量的引用
std::this_thread::sleep_for(std::chrono::milliseconds(100));
std::cout << "Accessing: " << local_data << std::endl; // 未定义行为!
});
t.detach(); // 线程继续运行,但local_data很快被销毁
// 函数结束,local_data被销毁,但分离的线程可能还在运行!
}
void safe_detach() {
std::string local_data = "Important data";
// 安全:通过值捕获,创建副本
std::thread t([data_copy = local_data]() { // C++14 初始化捕获
std::this_thread::sleep_for(std::chrono::milliseconds(100));
std::cout << "Accessing copy: " << data_copy << std::endl; // 安全
});
t.detach();
}
int main() {
std::cout << "=== Dangerous Detach ===" << std::endl;
dangerous_detach();
std::this_thread::sleep_for(std::chrono::milliseconds(200)); // 给线程时间运行
std::cout << "\n=== Safe Detach ===" << std::endl;
safe_detach();
std::this_thread::sleep_for(std::chrono::milliseconds(200));
return 0;
}
2. 重复 detach 和无效操作
cpp
#include <iostream>
#include <thread>
#include <system_error>
void demonstrate_detach_errors() {
std::thread t1([]{
std::cout << "Thread 1 running" << std::endl;
});
// 正确使用
t1.detach();
std::cout << "First detach successful" << std::endl;
// 错误:重复detach
try {
t1.detach(); // 抛出std::system_error
} catch (const std::system_error& e) {
std::cerr << "Error detaching already-detached thread: " << e.what() << std::endl;
}
// 错误:对已detach的线程调用join
try {
t1.join(); // 抛出std::system_error
} catch (const std::system_error& e) {
std::cerr << "Error joining detached thread: " << e.what() << std::endl;
}
// 默认构造的线程
std::thread t2;
try {
t2.detach(); // 抛出std::system_error
} catch (const std::system_error& e) {
std::cerr << "Error detaching default-constructed thread: " << e.what() << std::endl;
}
}
int main() {
demonstrate_detach_errors();
// 给第一个线程时间完成
std::this_thread::sleep_for(std::chrono::milliseconds(100));
return 0;
}
重要注意事项和使用细节
1. 生命周期管理最佳实践
cpp
#include <iostream>
#include <thread>
#include <memory>
class SafeDetachedTask {
private:
struct TaskData {
std::string config;
int timeout_ms;
TaskData(const std::string& cfg, int timeout)
: config(cfg), timeout_ms(timeout) {}
};
public:
void start_safe_task(const std::string& config, int timeout_ms) {
// 使用shared_ptr确保数据生命周期
auto task_data = std::make_shared<TaskData>(config, timeout_ms);
std::thread t([task_data]() {
std::cout << "Starting safe task with config: " << task_data->config << std::endl;
for (int i = 0; i < 3; ++i) {
std::cout << "Safe task working... (" << (i+1) << "/3)" << std::endl;
std::this_thread::sleep_for(
std::chrono::milliseconds(task_data->timeout_ms / 3));
}
std::cout << "Safe task completed" << std::endl;
});
t.detach();
std::cout << "Safe task detached and running independently" << std::endl;
}
};
int main() {
SafeDetachedTask task_runner;
task_runner.start_safe_task("production", 1500);
// 主线程立即继续
std::cout << "Main thread continuing..." << std::endl;
std::this_thread::sleep_for(std::chrono::seconds(2));
return 0;
}
2. 资源清理模式
cpp
#include <iostream>
#include <thread>
#include <atomic>
#include <vector>
class ResourceCleaner {
private:
std::atomic<int> active_tasks_{0};
std::vector<std::thread> cleanup_threads_;
public:
~ResourceCleaner() {
// 等待所有清理任务完成(最多等待一段时间)
auto start = std::chrono::steady_clock::now();
while (active_tasks_ > 0) {
if (std::chrono::steady_clock::now() - start > std::chrono::seconds(5)) {
std::cerr << "Timeout waiting for cleanup tasks" << std::endl;
break;
}
std::this_thread::sleep_for(std::chrono::milliseconds(100));
}
std::cout << "ResourceCleaner destroyed" << std::endl;
}
void schedule_cleanup(const std::string& resource_name) {
active_tasks_.fetch_add(1);
std::thread t([this, resource_name]() {
std::cout << "Cleaning up: " << resource_name << std::endl;
std::this_thread::sleep_for(std::chrono::milliseconds(500)); // 模拟清理工作
std::cout << "Completed cleanup: " << resource_name << std::endl;
active_tasks_.fetch_sub(1);
});
t.detach();
}
};
int main() {
{
ResourceCleaner cleaner;
// 安排多个清理任务
cleaner.schedule_cleanup("temp_file_1.txt");
cleaner.schedule_cleanup("cache_data");
cleaner.schedule_cleanup("network_connection");
std::cout << "Cleanup tasks scheduled, leaving scope..." << std::endl;
} // 析构函数会等待清理任务完成
std::cout << "Cleanup completed" << std::endl;
return 0;
}
总结
detach() 函数关键特性
| 特性 | 说明 |
|---|---|
| 函数声明 | void detach() |
| 参数 | 无 |
| 返回值 | 无 |
| 异常 | 可能抛出 std::system_error |
detach() 的有效调用条件
- 线程对象关联着活动线程 (
joinable() == true) - 线程尚未被 join 过
- 线程尚未被 detach 过
detach() 后的线程状态
| 操作 | 结果 |
|---|---|
joinable() |
返回 false |
get_id() |
返回默认的线程ID(不代表任何线程) |
join() |
抛出 std::system_error |
detach() |
抛出 std::system_error |
适用场景
- 守护线程/后台服务
- 异步日志记录
- 定期清理任务
- 监控和心跳检测
- 不需要结果的计算任务
危险场景和禁忌
- 访问局部变量(特别是通过引用捕获)
- 需要同步结果的任务
- 需要错误处理和异常传播的场景
- 资源生命周期难以管理的复杂场景
最佳实践
-
使用 shared_ptr 管理共享数据
cppauto data = std::make_shared<MyData>(); std::thread t([data] { /* 安全使用数据 */ }); t.detach(); -
避免捕获局部变量引用
cpp// 危险 std::thread t([&local] { /* 可能访问已销毁对象 */ }); // 安全 std::thread t([local] { /* 使用副本 */ }); -
提供监控机制
cpp// 使用atomic变量或promise/future监控状态 std::atomic<bool> completed{false}; std::thread t([&completed] { /* ... */ completed = true; }); t.detach(); -
清晰的资源管理策略
cpp// 确保所有资源都有明确的生命周期管理 class ManagedDetachedTask { std::shared_ptr<Resource> resource_; public: void start() { std::thread t([self = shared_from_this()] { // 安全访问resource_ }); t.detach(); } };
detach()是一个强大的工具,但需要谨慎使用。正确的资源管理和生命周期控制是使用分离线程的关键。在大多数情况下,优先考虑使用 join()和 RAII 模式,只有在确实需要独立运行的守护线程时才使用 detach()。
C++11 std::thread::swap() 函数
函数声明
成员函数版本
cpp
void swap(thread& other) noexcept;
非成员函数版本
cpp
void swap(thread& lhs, thread& rhs) noexcept;
参数说明
- 成员函数 :
other- 要与之交换的另一个线程对象 - 非成员函数 :
lhs,rhs- 要交换的两个线程对象
返回值
- 无返回值(void)
作用
交换两个线程对象的所有权,包括它们所管理的底层线程句柄
详细使用示例
1. 基本 swap() 成员函数使用
cpp
#include <iostream>
#include <thread>
#include <chrono>
void worker(int id) {
std::cout << "Worker " << id << " started in thread: "
<< std::this_thread::get_id() << std::endl;
std::this_thread::sleep_for(std::chrono::milliseconds(100));
std::cout << "Worker " << id << " completed" << std::endl;
}
int main() {
// 创建两个工作线程
std::thread t1(worker, 1);
std::thread t2(worker, 2);
std::cout << "Before swap:" << std::endl;
std::cout << "t1 ID: " << t1.get_id() << ", joinable: " << t1.joinable() << std::endl;
std::cout << "t2 ID: " << t2.get_id() << ", joinable: " << t2.joinable() << std::endl;
// 使用成员函数swap交换线程所有权
t1.swap(t2);
std::cout << "\nAfter swap:" << std::endl;
std::cout << "t1 ID: " << t1.get_id() << ", joinable: " << t1.joinable() << std::endl;
std::cout << "t2 ID: " << t2.get_id() << ", joinable: " << t2.joinable() << std::endl;
// 等待线程完成(注意:所有权已经交换)
if (t1.joinable()) t1.join(); // 现在t1管理原来的t2线程
if (t2.joinable()) t2.join(); // 现在t2管理原来的t1线程
return 0;
}
2. 非成员函数 swap() 使用
cpp
#include <iostream>
#include <thread>
#include <chrono>
void task(const std::string& name) {
std::cout << "Task '" << name << "' running in thread: "
<< std::this_thread::get_id() << std::endl;
std::this_thread::sleep_for(std::chrono::milliseconds(200));
}
int main() {
std::thread t1(task, "Alpha");
std::thread t2(task, "Beta");
std::thread t3; // 空线程
std::cout << "Initial state:" << std::endl;
std::cout << "t1: " << (t1.joinable() ? "active" : "empty") << std::endl;
std::cout << "t2: " << (t2.joinable() ? "active" : "empty") << std::endl;
std::cout << "t3: " << (t3.joinable() ? "active" : "empty") << std::endl;
// 使用非成员函数swap
std::swap(t1, t2); // 交换t1和t2
std::cout << "\nAfter swapping t1 and t2:" << std::endl;
std::cout << "t1: " << (t1.joinable() ? "active" : "empty") << std::endl;
std::cout << "t2: " << (t2.joinable() ? "active" : "empty") << std::endl;
std::swap(t2, t3); // 交换t2和t3(将活动线程移动到t3)
std::cout << "\nAfter swapping t2 and t3:" << std::endl;
std::cout << "t2: " << (t2.joinable() ? "active" : "empty") << std::endl;
std::cout << "t3: " << (t3.joinable() ? "active" : "empty") << std::endl;
// 等待剩余的活跃线程
if (t1.joinable()) t1.join();
if (t3.joinable()) t3.join();
return 0;
}
3. 线程排序和优先级管理
cpp
#include <iostream>
#include <thread>
#include <vector>
#include <algorithm>
#include <chrono>
class ThreadManager {
private:
std::vector<std::thread> threads;
std::vector<int> priorities; // 线程优先级
public:
// 添加线程及其优先级
void add_thread(std::thread&& t, int priority) {
threads.push_back(std::move(t));
priorities.push_back(priority);
}
// 根据优先级对线程进行排序
void sort_by_priority() {
// 创建索引数组
std::vector<size_t> indices(threads.size());
for (size_t i = 0; i < indices.size(); ++i) {
indices[i] = i;
}
// 根据优先级对索引进行排序(降序)
std::sort(indices.begin(), indices.end(), [this](size_t a, size_t b) {
return priorities[a] > priorities[b]; // 优先级高的在前
});
// 应用排序到线程数组
std::vector<std::thread> sorted_threads;
std::vector<int> sorted_priorities;
for (size_t idx : indices) {
sorted_threads.push_back(std::move(threads[idx]));
sorted_priorities.push_back(priorities[idx]);
}
threads = std::move(sorted_threads);
priorities = std::move(sorted_priorities);
}
// 等待所有线程完成
void join_all() {
for (size_t i = 0; i < threads.size(); ++i) {
if (threads[i].joinable()) {
std::cout << "Joining thread with priority " << priorities[i] << std::endl;
threads[i].join();
}
}
}
// 显示当前线程状态
void print_status() const {
std::cout << "Thread status:" << std::endl;
for (size_t i = 0; i < threads.size(); ++i) {
std::cout << " Thread " << i << ": priority=" << priorities[i]
<< ", joinable=" << threads[i].joinable() << std::endl;
}
}
};
void prioritized_worker(int priority, int duration_ms) {
std::cout << "Priority " << priority << " worker started" << std::endl;
std::this_thread::sleep_for(std::chrono::milliseconds(duration_ms));
std::cout << "Priority " << priority << " worker completed" << std::endl;
}
int main() {
ThreadManager manager;
// 添加不同优先级的线程(故意乱序添加)
manager.add_thread(std::thread(prioritized_worker, 1, 300), 1);
manager.add_thread(std::thread(prioritized_worker, 3, 100), 3);
manager.add_thread(std::thread(prioritized_worker, 2, 200), 2);
manager.add_thread(std::thread(prioritized_worker, 5, 50), 5); // 最高优先级
std::cout << "Before sorting:" << std::endl;
manager.print_status();
// 根据优先级排序线程
manager.sort_by_priority();
std::cout << "\nAfter sorting by priority:" << std::endl;
manager.print_status();
// 按优先级顺序等待线程(高优先级先等待)
std::cout << "\nJoining threads in priority order:" << std::endl;
manager.join_all();
return 0;
}
4. 线程池中的线程交换
cpp
#include <iostream>
#include <thread>
#include <vector>
#include <queue>
#include <functional>
#include <mutex>
#include <condition_variable>
#include <atomic>
class DynamicThreadPool {
private:
std::vector<std::thread> workers;
std::queue<std::function<void()>> tasks;
std::mutex queue_mutex;
std::condition_variable condition;
std::atomic<bool> stop;
public:
DynamicThreadPool(size_t initial_size) : stop(false) {
for (size_t i = 0; i < initial_size; ++i) {
workers.emplace_back(&DynamicThreadPool::worker_loop, this);
}
}
~DynamicThreadPool() {
stop = true;
condition.notify_all();
for (auto& worker : workers) {
if (worker.joinable()) {
worker.join();
}
}
}
// 添加任务
template<class F>
void enqueue(F&& f) {
{
std::lock_guard<std::mutex> lock(queue_mutex);
tasks.emplace(std::forward<F>(f));
}
condition.notify_one();
}
// 调整线程池大小
void resize(size_t new_size) {
std::lock_guard<std::mutex> lock(queue_mutex);
if (new_size > workers.size()) {
// 需要增加线程
size_t to_add = new_size - workers.size();
for (size_t i = 0; i < to_add; ++i) {
workers.emplace_back(&DynamicThreadPool::worker_loop, this);
std::cout << "Added thread, total: " << workers.size() << std::endl;
}
} else if (new_size < workers.size()) {
// 需要减少线程(标记停止,但让它们完成当前任务)
size_t to_remove = workers.size() - new_size;
// 实际实现中需要更复杂的逻辑来安全减少线程
std::cout << "Thread reduction requested (not implemented in this example)" << std::endl;
}
}
// 交换两个线程池的工作线程(高级用法)
void swap_thread(DynamicThreadPool& other, size_t index1, size_t index2) {
if (index1 < workers.size() && index2 < other.workers.size()) {
// 注意:这需要非常小心的同步处理
// 在实际应用中,可能需要停止线程或确保它们处于安全状态
std::swap(workers[index1], other.workers[index2]);
std::cout << "Swapped thread " << index1 << " with thread " << index2 << std::endl;
}
}
size_t size() const {
return workers.size();
}
private:
void worker_loop() {
while (!stop) {
std::function<void()> task;
{
std::unique_lock<std::mutex> lock(queue_mutex);
condition.wait(lock, [this] {
return stop || !tasks.empty();
});
if (stop && tasks.empty()) {
return;
}
task = std::move(tasks.front());
tasks.pop();
}
task();
}
}
};
int main() {
DynamicThreadPool pool1(2);
DynamicThreadPool pool2(3);
std::cout << "Initial pool sizes: " << std::endl;
std::cout << "Pool 1: " << pool1.size() << " threads" << std::endl;
std::cout << "Pool 2: " << pool2.size() << " threads" << std::endl;
// 添加一些测试任务
for (int i = 0; i < 5; ++i) {
pool1.enqueue([i] {
std::cout << "Pool1 task " << i << std::endl;
std::this_thread::sleep_for(std::chrono::milliseconds(100));
});
pool2.enqueue([i] {
std::cout << "Pool2 task " << i << std::endl;
std::this_thread::sleep_for(std::chrono::milliseconds(100));
});
}
// 调整线程池大小
pool1.resize(4);
pool2.resize(1);
std::cout << "\nAfter resizing: " << std::endl;
std::cout << "Pool 1: " << pool1.size() << " threads" << std::endl;
std::cout << "Pool 2: " << pool2.size() << " threads" << std::endl;
// 给任务一些时间执行
std::this_thread::sleep_for(std::chrono::seconds(1));
return 0;
}
5. 异常安全的线程交换
cpp
#include <iostream>
#include <thread>
#include <stdexcept>
#include <utility>
class ExceptionSafeThreadSwapper {
public:
// 异常安全的线程交换
static bool safe_swap(std::thread& a, std::thread& b) noexcept {
try {
// swap是noexcept的,但为了演示安全模式
a.swap(b);
return true;
} catch (...) {
// std::thread::swap是noexcept,所以这里通常不会执行
std::cerr << "Unexpected error during thread swap" << std::endl;
return false;
}
}
// 带状态检查的交换
static bool conditional_swap(std::thread& a, std::thread& b,
bool check_joinable = true) {
if (check_joinable) {
// 只有两个线程都可join或都不可join时才交换
if (a.joinable() != b.joinable()) {
std::cout << "Swap condition not met: joinable states differ" << std::endl;
return false;
}
}
a.swap(b);
std::cout << "Threads swapped successfully" << std::endl;
return true;
}
// 交换并保证资源清理
static void swap_with_cleanup(std::thread& a, std::thread& b) {
std::thread temp; // 空线程
// 使用临时变量进行安全交换
temp.swap(a); // a的内容移到temp
a.swap(b); // b的内容移到a
b.swap(temp); // temp的内容(a的原始内容)移到b
// temp现在为空,确保资源被正确转移
if (!temp.joinable()) {
std::cout << "Cleanup swap completed successfully" << std::endl;
}
}
};
void worker(const std::string& name) {
std::cout << name << " working..." << std::endl;
std::this_thread::sleep_for(std::chrono::milliseconds(100));
}
int main() {
std::thread t1(worker, "Thread 1");
std::thread t2(worker, "Thread 2");
std::thread t3; // 空线程
std::cout << "=== Testing Safe Swap ===" << std::endl;
bool success = ExceptionSafeThreadSwapper::safe_swap(t1, t2);
std::cout << "Swap success: " << std::boolalpha << success << std::endl;
std::cout << "\n=== Testing Conditional Swap ===" << std::endl;
// 这个会失败,因为joinable状态不同
success = ExceptionSafeThreadSwapper::conditional_swap(t1, t3);
std::cout << "Conditional swap success: " << success << std::endl;
// 这个会成功
std::thread t4(worker, "Thread 4");
success = ExceptionSafeThreadSwapper::conditional_swap(t1, t4);
std::cout << "Conditional swap success: " << success << std::endl;
std::cout << "\n=== Testing Cleanup Swap ===" << std::endl;
ExceptionSafeThreadSwapper::swap_with_cleanup(t2, t4);
// 等待所有活动线程
if (t1.joinable()) t1.join();
if (t2.joinable()) t2.join();
if (t4.joinable()) t4.join();
return 0;
}
swap() 的特殊用例和技巧
1. 实现线程的"移动"语义
cpp
#include <iostream>
#include <thread>
#include <vector>
class ThreadMover {
public:
// 使用swap实现移动语义
static std::thread move_thread(std::thread& t) {
std::thread temp;
temp.swap(t); // 将t的内容移动到temp
return temp; // 返回移动后的线程
}
// 将线程移动到vector中
static void move_to_vector(std::thread& t, std::vector<std::thread>& container) {
container.push_back(std::thread()); // 添加空线程
container.back().swap(t); // 交换内容
}
};
int main() {
std::vector<std::thread> thread_pool;
// 创建一些线程
std::thread t1([]{ std::cout << "Thread 1" << std::endl; });
std::thread t2([]{ std::cout << "Thread 2" << std::endl; });
// 使用swap将线程移动到vector中
ThreadMover::move_to_vector(t1, thread_pool);
ThreadMover::move_to_vector(t2, thread_pool);
std::cout << "Original threads are now empty: "
<< !t1.joinable() << ", " << !t2.joinable() << std::endl;
std::cout << "Thread pool size: " << thread_pool.size() << std::endl;
// 从vector中移动线程出来
std::thread retrieved = ThreadMover::move_thread(thread_pool[0]);
std::cout << "Retrieved thread joinable: " << retrieved.joinable() << std::endl;
std::cout << "Vector thread now empty: " << !thread_pool[0].joinable() << std::endl;
// 清理
if (retrieved.joinable()) retrieved.join();
for (auto& t : thread_pool) {
if (t.joinable()) t.join();
}
return 0;
}
2. 线程状态跟踪和调试
cpp
#include <iostream>
#include <thread>
#include <map>
#include <iomanip>
class ThreadTracker {
private:
std::map<std::thread::id, std::string> thread_names;
public:
void register_thread(const std::thread& t, const std::string& name) {
thread_names[t.get_id()] = name;
}
void track_swap(const std::thread& a, const std::thread& b, const std::string& operation) {
std::cout << "=== Thread Swap Operation: " << operation << " ===" << std::endl;
std::cout << "Thread A: " << std::setw(20) << a.get_id()
<< " [" << (a.joinable() ? "active" : "empty") << "]" << std::endl;
std::cout << "Thread B: " << std::setw(20) << b.get_id()
<< " [" << (b.joinable() ? "active" : "empty") << "]" << std::endl;
auto it_a = thread_names.find(a.get_id());
auto it_b = thread_names.find(b.get_id());
if (it_a != thread_names.end()) {
std::cout << " Thread A name: " << it_a->second << std::endl;
}
if (it_b != thread_names.end()) {
std::cout << " Thread B name: " << it_b->second << std::endl;
}
std::cout << std::endl;
}
void print_all_threads() const {
std::cout << "=== Registered Threads ===" << std::endl;
for (const auto& pair : thread_names) {
std::cout << std::setw(20) << pair.first << " : " << pair.second << std::endl;
}
std::cout << std::endl;
}
};
int main() {
ThreadTracker tracker;
std::thread t1([]{
std::this_thread::sleep_for(std::chrono::milliseconds(100));
});
std::thread t2([]{
std::this_thread::sleep_for(std::chrono::milliseconds(100));
});
// 注册线程名称
tracker.register_thread(t1, "Worker_Alpha");
tracker.register_thread(t2, "Worker_Beta");
tracker.print_all_threads();
tracker.track_swap(t1, t2, "Before swap");
// 执行交换
t1.swap(t2);
tracker.track_swap(t1, t2, "After swap");
// 注意:线程ID不会改变,改变的是线程对象管理的线程
std::cout << "Important: swap() exchanges thread ownership, not thread IDs!" << std::endl;
if (t1.joinable()) t1.join();
if (t2.joinable()) t2.join();
return 0;
}
重要注意事项和使用细节
1. swap() 不会改变线程ID
cpp
#include <iostream>
#include <thread>
void demonstrate_id_behavior() {
std::thread t1([]{});
std::thread t2([]{});
std::thread::id id1_before = t1.get_id();
std::thread::id id2_before = t2.get_id();
std::cout << "Before swap:" << std::endl;
std::cout << "t1 ID: " << id1_before << std::endl;
std::cout << "t2 ID: " << id2_before << std::endl;
t1.swap(t2);
std::thread::id id1_after = t1.get_id();
std::thread::id id2_after = t2.get_id();
std::cout << "After swap:" << std::endl;
std::cout << "t1 ID: " << id1_after << std::endl;
std::cout << "t2 ID: " << id2_after << std::endl;
// 重要:线程ID保持不变,交换的是线程对象的所有权
std::cout << "t1 ID changed: " << (id1_before != id1_after) << std::endl; // false
std::cout << "t2 ID changed: " << (id2_before != id2_after) << std::endl; // false
if (t1.joinable()) t1.join();
if (t2.joinable()) t2.join();
}
2. 自交换安全性
cpp
#include <iostream>
#include <thread>
void self_swap_safety() {
std::thread t([]{
std::cout << "Thread running" << std::endl;
});
std::cout << "Before self-swap: joinable = " << t.joinable() << std::endl;
// 自交换是安全的(无操作)
t.swap(t);
std::cout << "After self-swap: joinable = " << t.joinable() << std::endl;
if (t.joinable()) t.join();
}
int main() {
self_swap_safety();
return 0;
}
总结
swap() 函数关键特性
| 特性 | 说明 |
|---|---|
| 函数声明 | void swap(thread& other) noexcept(成员函数) |
| 参数 | 要交换的另一个线程对象 |
| 返回值 | 无 |
| 异常安全 | noexcept(不会抛出异常) |
swap() 的作用和效果
- 交换线程所有权:两个线程对象交换它们所管理的底层线程句柄
- 不改变线程ID:线程的实际标识符保持不变
- joinable状态交换:两个线程对象的可连接状态也会交换
使用场景
- 线程资源管理:在容器中重新排列线程
- 优先级调整:根据优先级重新组织线程执行顺序
- 线程池优化:动态调整工作线程分配
- 调试和测试:跟踪线程状态和所有权变化
- 资源清理:安全地转移线程所有权
重要注意事项
- 线程ID不变 :
swap()交换的是线程对象的所有权,不是线程本身的标识 - 自交换安全 :
t.swap(t)是安全的无操作 - 异常安全 :
swap()是noexcept的,不会抛出异常 - 移动语义基础 :
swap()是实现移动构造和移动赋值的基础 - 标准库兼容 :支持
std::swap()算法
最佳实践
-
优先使用标准算法:
cppstd::swap(t1, t2); // 非成员函数版本 -
确保异常安全:
cpp// swap是noexcept的,但还是要确保资源管理正确 void safe_operation(std::thread& a, std::thread& b) { std::thread temp; temp.swap(a); // 备份a try { a.swap(b); // 主要操作 b.swap(temp); // 完成交换 } catch (...) { // 异常处理 a.swap(temp); // 恢复a throw; } } -
结合RAII模式:
cppclass ThreadWrapper { std::thread t; public: void swap(ThreadWrapper& other) noexcept { t.swap(other.t); } // ... 其他成员函数 };
swap()是 std::thread的重要操作,它为线程资源管理提供了灵活性和安全性,是实现高级线程管理模式的基础工具。
C++11 std::this_thread 命名空间
概述
std::this_thread命名空间提供了一组访问当前线程的函数,用于线程管理、同步和调度。
1. get_id() 函数
函数声明
cpp
std::thread::id get_id() noexcept;
参数
- 无参数
返回值
std::thread::id:当前线程的唯一标识符
作用
获取当前执行线程的唯一标识符
使用示例
cpp
#include <iostream>
#include <thread>
#include <vector>
#include <map>
void worker(int id) {
std::cout << "Worker " << id << " running in thread: "
<< std::this_thread::get_id() << std::endl;
}
void demonstrate_get_id() {
std::cout << "Main thread ID: " << std::this_thread::get_id() << std::endl;
// 存储线程ID和任务的映射
std::map<std::thread::id, std::string> thread_tasks;
std::vector<std::thread> threads;
// 创建多个工作线程
for (int i = 0; i < 3; ++i) {
threads.emplace_back([i, &thread_tasks]() {
std::string task_name = "Task_" + std::to_string(i);
thread_tasks[std::this_thread::get_id()] = task_name;
std::cout << "Executing " << task_name
<< " in thread: " << std::this_thread::get_id() << std::endl;
});
}
// 等待所有线程完成
for (auto& t : threads) {
t.join();
}
// 输出线程任务映射
std::cout << "\nThread Task Mapping:" << std::endl;
for (const auto& pair : thread_tasks) {
std::cout << "Thread " << pair.first << " -> " << pair.second << std::endl;
}
}
int main() {
demonstrate_get_id();
return 0;
}
注意事项
- 主线程也有唯一ID:主线程的ID与工作线程不同
- ID比较安全:可以安全地比较不同线程的ID
- 哈希支持 :
std::thread::id支持哈希,可用于关联容器 - 空线程ID :默认构造的
std::thread::id表示"非线程"
使用细节
cpp
// 线程ID的比较和哈希
std::thread::id main_id = std::this_thread::get_id();
std::hash<std::thread::id> hasher;
size_t hash_value = hasher(main_id);
// 线程本地存储的键
thread_local std::thread::id this_thread_id = std::this_thread::get_id();
2. yield() 函数
函数声明
cpp
void yield() noexcept;
参数
- 无参数
返回值
- 无返回值
作用
提示调度器让出当前线程的时间片,允许其他线程运行
使用示例
cpp
#include <iostream>
#include <thread>
#include <atomic>
#include <chrono>
class SpinLock {
private:
std::atomic<bool> locked_{false};
public:
void lock() {
// 自旋锁:使用yield避免忙等待消耗CPU
while (locked_.exchange(true, std::memory_order_acquire)) {
std::this_thread::yield(); // 让出CPU,减少竞争
}
}
void unlock() {
locked_.store(false, std::memory_order_release);
}
};
void worker_with_yield(int id, std::atomic<int>& counter, SpinLock& lock) {
for (int i = 0; i < 100; ++i) {
lock.lock();
int current = counter.load();
std::this_thread::sleep_for(std::chrono::microseconds(10)); // 模拟工作
counter.store(current + 1);
lock.unlock();
// 在锁外使用yield,给其他线程机会
std::this_thread::yield();
}
std::cout << "Worker " << id << " completed" << std::endl;
}
void demonstrate_yield() {
SpinLock lock;
std::atomic<int> counter{0};
std::vector<std::thread> threads;
// 创建多个竞争线程
for (int i = 0; i < 4; ++i) {
threads.emplace_back(worker_with_yield, i, std::ref(counter), std::ref(lock));
}
// 等待所有线程完成
for (auto& t : threads) {
t.join();
}
std::cout << "Final counter value: " << counter << std::endl;
}
// 生产者-消费者模式中的yield使用
class MessageQueue {
private:
std::queue<int> queue_;
std::mutex mutex_;
std::condition_variable cv_;
public:
void produce(int value) {
std::lock_guard<std::mutex> lock(mutex_);
queue_.push(value);
cv_.notify_one();
}
int consume() {
std::unique_lock<std::mutex> lock(mutex_);
// 使用yield的忙等待模式(不推荐,仅用于演示)
while (queue_.empty()) {
lock.unlock();
std::this_thread::yield(); // 让出CPU
lock.lock();
}
int value = queue_.front();
queue_.pop();
return value;
}
};
int main() {
demonstrate_yield();
return 0;
}
注意事项
- 提示而非强制 :
yield()只是建议,调度器可能忽略 - 避免过度使用:不合理的yield可能降低性能
- 替代忙等待:比纯自旋锁更友好
- 不适合精确同步:不能保证特定线程获得执行权
使用细节
cpp
// 正确的yield使用模式
while (!condition_met()) {
std::this_thread::yield(); // 而不是忙等待
}
// 与sleep_for的区别
std::this_thread::yield(); // 立即重新调度
std::this_thread::sleep_for(1ms); // 至少睡眠指定时间
3. sleep_until() 函数
函数声明
cpp
template<class Clock, class Duration>
void sleep_until(const std::chrono::time_point<Clock, Duration>& sleep_time);
参数
sleep_time:要阻塞直到达到的时间点
返回值
- 无返回值
作用
阻塞当前线程直到达到指定的时间点
使用示例
cpp
#include <iostream>
#include <thread>
#include <chrono>
#include <iomanip>
void precise_timer_example() {
auto start = std::chrono::steady_clock::now();
// 精确的定时任务:每秒执行一次
for (int i = 1; i <= 5; ++i) {
// 计算下一次执行的时间点
auto next_time = start + std::chrono::seconds(i);
// 睡眠直到精确时间点
std::this_thread::sleep_until(next_time);
auto current_time = std::chrono::steady_clock::now();
auto drift = std::chrono::duration_cast<std::chrono::milliseconds>(
current_time - next_time);
std::cout << "Tick " << i << " - Drift: " << drift.count() << "ms" << std::endl;
}
}
void scheduled_task() {
// 安排任务在特定时间执行
auto scheduled_time = std::chrono::system_clock::now() + std::chrono::seconds(2);
std::cout << "Task scheduled for: "
<< std::chrono::system_clock::to_time_t(scheduled_time) << std::endl;
std::this_thread::sleep_until(scheduled_time);
std::cout << "Task executed at: "
<< std::chrono::system_clock::to_time_t(std::chrono::system_clock::now())
<< std::endl;
}
class RateLimiter {
private:
std::chrono::steady_clock::time_point next_available_;
std::chrono::milliseconds interval_;
public:
RateLimiter(int rate_per_second)
: next_available_(std::chrono::steady_clock::now()),
interval_(1000 / rate_per_second) {}
void acquire() {
auto now = std::chrono::steady_clock::now();
if (now < next_available_) {
// 速率限制:睡眠直到下一个可用时间点
std::this_thread::sleep_until(next_available_);
}
next_available_ = std::chrono::steady_clock::now() + interval_;
}
};
void demonstrate_rate_limiting() {
RateLimiter limiter(2); // 每秒最多2次
for (int i = 0; i < 6; ++i) {
limiter.acquire();
std::cout << "Operation " << i + 1 << " at: "
<< std::chrono::duration_cast<std::chrono::milliseconds>(
std::chrono::steady_clock::now().time_since_epoch()).count()
<< "ms" << std::endl;
}
}
int main() {
std::cout << "=== Precise Timer Example ===" << std::endl;
precise_timer_example();
std::cout << "\n=== Scheduled Task ===" << std::endl;
scheduled_task();
std::cout << "\n=== Rate Limiting ===" << std::endl;
demonstrate_rate_limiting();
return 0;
}
注意事项
- 时钟类型 :可以使用
system_clock、steady_clock、high_resolution_clock - 可能提前唤醒:系统调度可能提前唤醒线程
- 绝对时间:基于时间点而非持续时间
- 时钟稳定性 :
steady_clock更适合精确计时
使用细节
cpp
// 使用不同的时钟类型
auto system_time = std::chrono::system_clock::now() + std::chrono::seconds(1);
auto steady_time = std::chrono::steady_clock::now() + std::chrono::seconds(1);
std::this_thread::sleep_until(system_time); // 系统时钟
std::this_thread::sleep_until(steady_time); // 稳定时钟
4. sleep_for() 函数
函数声明
cpp
template<class Rep, class Period>
void sleep_for(const std::chrono::duration<Rep, Period>& sleep_duration);
参数
sleep_duration:要阻塞的时间长度
返回值
- 无返回值
作用
阻塞当前线程指定的时间长度
使用示例
cpp
#include <iostream>
#include <thread>
#include <chrono>
#include <atomic>
void simple_delay() {
std::cout << "Starting delay..." << std::endl;
// 睡眠2秒
std::this_thread::sleep_for(std::chrono::seconds(2));
std::cout << "Delay completed" << std::endl;
}
void periodic_task() {
std::atomic<bool> running{true};
int iteration = 0;
// 捕获Ctrl+C的信号处理(简化版)
std::thread task_thread([&running, &iteration]() {
while (running) {
std::cout << "Periodic task iteration: " << ++iteration << std::endl;
// 每秒执行一次
std::this_thread::sleep_for(std::chrono::seconds(1));
}
std::cout << "Task stopped" << std::endl;
});
// 主线程等待一段时间后停止任务
std::this_thread::sleep_for(std::chrono::seconds(5));
running = false;
task_thread.join();
}
class RetryMechanism {
private:
int max_retries_;
std::chrono::milliseconds base_delay_;
public:
RetryMechanism(int max_retries, int base_delay_ms)
: max_retries_(max_retries), base_delay_(base_delay_ms) {}
template<typename Operation>
bool execute_with_retry(Operation&& op) {
for (int attempt = 1; attempt <= max_retries_; ++attempt) {
try {
op();
std::cout << "Operation succeeded on attempt " << attempt << std::endl;
return true;
} catch (const std::exception& e) {
std::cout << "Attempt " << attempt << " failed: " << e.what() << std::endl;
if (attempt == max_retries_) {
std::cout << "Max retries exceeded" << std::endl;
return false;
}
// 指数退避策略
auto delay = base_delay_ * (1 << (attempt - 1));
std::cout << "Retrying in " << delay.count() << "ms..." << std::endl;
std::this_thread::sleep_for(delay);
}
}
return false;
}
};
void demonstrate_retry() {
RetryMechanism retry(3, 100); // 最多3次重试,基础延迟100ms
int attempt_count = 0;
retry.execute_with_retry([&attempt_count]() {
attempt_count++;
std::cout << "Execution attempt: " << attempt_count << std::endl;
// 模拟失败(前两次失败,第三次成功)
if (attempt_count < 3) {
throw std::runtime_error("Simulated failure");
}
std::cout << "Operation successful!" << std::endl;
});
}
void precise_timing_comparison() {
auto start = std::chrono::steady_clock::now();
// 使用sleep_for进行不精确的定时
for (int i = 0; i < 5; ++i) {
auto target_time = start + std::chrono::seconds(i + 1);
std::this_thread::sleep_for(std::chrono::seconds(1));
auto actual_time = std::chrono::steady_clock::now();
auto error = std::chrono::duration_cast<std::chrono::milliseconds>(
actual_time - target_time);
std::cout << "Iteration " << i + 1 << " - Timing error: "
<< error.count() << "ms" << std::endl;
}
}
int main() {
std::cout << "=== Simple Delay ===" << std::endl;
simple_delay();
std::cout << "\n=== Periodic Task ===" << std::endl;
periodic_task();
std::cout << "\n=== Retry Mechanism ===" << std::endl;
demonstrate_retry();
std::cout << "\n=== Timing Comparison ===" << std::endl;
precise_timing_comparison();
return 0;
}
注意事项
- 最小睡眠时间:实际睡眠时间可能长于请求的时间
- 信号中断:可能被信号中断
- 相对时间:基于持续时间而非绝对时间点
- 资源友好:比忙等待更节省CPU资源
使用细节
cpp
// 不同的时间单位
std::this_thread::sleep_for(std::chrono::hours(1)); // 小时
std::this_thread::sleep_for(std::chrono::minutes(30)); // 分钟
std::this_thread::sleep_for(std::chrono::seconds(10)); // 秒
std::this_thread::sleep_for(std::chrono::milliseconds(100)); // 毫秒
std::this_thread::sleep_for(std::chrono::microseconds(500)); // 微秒
// 使用字面量(C++14)
using namespace std::chrono_literals;
std::this_thread::sleep_for(100ms); // 100毫秒
std::this_thread::sleep_for(2s); // 2秒
综合应用示例
高级线程调度器
cpp
#include <iostream>
#include <thread>
#include <chrono>
#include <queue>
#include <vector>
#include <functional>
#include <atomic>
#include <condition_variable>
class AdvancedScheduler {
private:
struct ScheduledTask {
std::chrono::steady_clock::time_point scheduled_time;
std::function<void()> task;
int priority;
bool operator<(const ScheduledTask& other) const {
// 优先级高的先执行,时间早的先执行
if (priority != other.priority) {
return priority < other.priority;
}
return scheduled_time > other.scheduled_time;
}
};
std::priority_queue<ScheduledTask> task_queue_;
std::atomic<bool> running_{false};
std::thread scheduler_thread_;
public:
AdvancedScheduler() : running_(false) {}
~AdvancedScheduler() {
stop();
}
void start() {
if (running_.exchange(true)) {
return; // 已经在运行
}
scheduler_thread_ = std::thread([this]() {
scheduler_loop();
});
}
void stop() {
if (running_.exchange(false)) {
if (scheduler_thread_.joinable()) {
scheduler_thread_.join();
}
}
}
void schedule(std::function<void()> task, int delay_ms, int priority = 0) {
auto scheduled_time = std::chrono::steady_clock::now() +
std::chrono::milliseconds(delay_ms);
ScheduledTask new_task{scheduled_time, std::move(task), priority};
// 注意:实际实现需要线程安全的队列
// 这里简化处理,仅用于演示
task_queue_.push(new_task);
}
private:
void scheduler_loop() {
while (running_) {
if (task_queue_.empty()) {
std::this_thread::sleep_for(std::chrono::milliseconds(10));
continue;
}
auto next_task = task_queue_.top();
auto now = std::chrono::steady_clock::now();
if (now >= next_task.scheduled_time) {
// 执行任务
task_queue_.pop();
next_task.task();
} else {
// 使用sleep_until精确等待
std::this_thread::sleep_until(next_task.scheduled_time);
}
// 让出CPU,避免饥饿
std::this_thread::yield();
}
}
};
int main() {
AdvancedScheduler scheduler;
std::cout << "Starting advanced scheduler..." << std::endl;
scheduler.start();
// 安排多个任务
scheduler.schedule([]() {
std::cout << "High priority task executed in thread: "
<< std::this_thread::get_id() << std::endl;
}, 1000, 10); // 1秒后执行,优先级10
scheduler.schedule([]() {
std::cout << "Normal priority task executed" << std::endl;
}, 2000, 5); // 2秒后执行,优先级5
scheduler.schedule([]() {
std::cout << "Low priority task executed" << std::endl;
}, 1500, 1); // 1.5秒后执行,优先级1
// 等待任务执行
std::this_thread::sleep_for(std::chrono::seconds(3));
std::cout << "Stopping scheduler..." << std::endl;
scheduler.stop();
return 0;
}
总结对比
| 函数 | 参数类型 | 作用 | 适用场景 |
|---|---|---|---|
get_id() |
无 | 获取线程ID | 调试、日志、线程识别 |
yield() |
无 | 让出CPU时间片 | 自旋锁、协作式多任务 |
sleep_until() |
时间点 | 阻塞到指定时间 | 精确调度、定时任务 |
sleep_for() |
时间段 | 阻塞指定时长 | 延迟、重试、节流 |
关键要点
- 线程识别 :
get_id()用于调试和监控 - 协作调度 :
yield()用于改善多线程性能 - 绝对定时 :
sleep_until()用于精确的时间点控制 - 相对延迟 :
sleep_for()用于简单的延迟操作
最佳实践
- 优先使用
sleep_until()进行精确计时 - 谨慎使用
yield(),避免不必要的上下文切换 - 结合RAII模式管理线程资源
- 考虑时钟稳定性选择适当的时钟类型