C++ thread类
C++ thread类
C++11 std::thread 构造函数
1. 默认构造函数 (1)
函数声明
thread() noexcept;
作用
创建一个不关联任何线程的线程对象(空线程对象)
使用示例
#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)
函数声明
template <class Fn, class... Args>
explicit thread (Fn&& fn, Args&&... args);
参数说明
fn: 可调用对象(函数、函数指针、成员函数指针、函数对象、lambda表达式等)args...: 传递给可调用对象的参数包
作用
创建新线程并立即开始执行指定的可调用对象
使用示例
普通函数
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 表达式
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;
}
成员函数
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)
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;
}
参数传递细节
值传递(默认)
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)
void modify_value(int& val) {val = 100;
}int main() {int x = 50;std::thread t(modify_value, std::ref(x)); // 必须使用 std::reft.join();std::cout << "x = " << x << std::endl; // 输出 100(已改变)return 0;
}
移动语义
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; // 输出 0return 0;
}
3. 拷贝构造函数 [deleted] (3)
函数声明
thread (const thread&) = delete;
作用
明确表示线程对象不可拷贝(编译时错误)
使用示例
std::thread t1([](){std::cout << "Thread 1" << std::endl;
});// 编译错误:尝试拷贝线程对象
// std::thread t2 = t1; // ERROR!// 编译错误:拷贝构造
// std::thread t2(t1); // ERROR!
设计原因
- 防止多个线程对象管理同一个线程
- 确保线程资源的唯一所有权
- 避免资源管理混乱
4. 移动构造函数 (4)
函数声明
thread (thread&& x) noexcept;
作用
将线程所有权从一个对象转移到另一个对象
使用示例
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;
}
移动语义的实际应用
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. 线程对象生命周期管理
// 危险:临时线程对象立即析构
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. 异常安全
void risky_operation() {std::thread t([](){// 一些工作});// 如果这里抛出异常,t 可能没有被 join/detach// throw std::runtime_error("Something went wrong");// 解决方案:使用 RAIIif (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. 参数求值顺序
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:
#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)
函数声明
thread& operator= (thread&& rhs) noexcept;
参数说明
rhs: 右值引用,指向要移动的源线程对象
返回值
- 返回当前对象的引用(
*this) - 支持链式赋值操作
作用
将另一个线程对象的所有权移动到当前对象
使用示例
基本移动赋值
#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; // 0std::cout << "t2 joinable: " << t2.joinable() << std::endl; // 1// 移动赋值:将 t2 的所有权转移给 t1t1 = std::move(t2);std::cout << "\nAfter move assignment:" << std::endl;std::cout << "t1 joinable: " << t1.joinable() << std::endl; // 1std::cout << "t2 joinable: " << t2.joinable() << std::endl; // 0if (t1.joinable()) {t1.join();}return 0;
}
自赋值安全性
std::thread t(worker, 1);// 自赋值检查:标准要求是安全的
t = std::move(t); // 自赋值,标准要求无操作if (t.joinable()) {t.join(); // 仍然可以正常 join
}
链式赋值
std::thread t1, t2, t3;// 链式移动赋值
t1 = std::move(t2 = std::move(std::thread(worker, 1)));if (t1.joinable()) {t1.join();
}
移动语义的实际应用场景
线程池中的线程管理
#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;
}
线程所有权的动态转移
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)
函数声明
thread& operator= (const thread&) = delete;
作用
明确禁止线程对象的拷贝赋值操作
设计原因
- 确保线程资源的唯一所有权
- 防止多个线程对象管理同一个底层线程
- 避免资源管理混乱和竞态条件
使用示例(错误演示)
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 functiont1.join();
重要注意事项和使用细节
1. 自我赋值安全性
std::thread t(worker, 1);// 标准要求移动赋值运算符必须处理自我赋值
t = std::move(t); // 安全的,t 仍然有效if (t.joinable()) {t.join(); // 正常工作
}
2. 移动后的源对象状态
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. 异常安全性
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;// 异常安全:只需要管理 t2if (t2.joinable()) {t2.join();}// t1 已经是空状态,无需管理}
}
4. 资源管理模式
RAII 包装器示例
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);// 析构时自动 joinreturn 0;
}
5. 容器中的线程管理
// 在标准容器中存储线程对象
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. 条件赋值模式
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) - 任何拷贝赋值尝试都会导致编译错误
- 设计目的是确保线程所有权的唯一性
最佳实践
-
总是检查移动后的状态
t2 = std::move(t1); // t1 现在为空,只能进行无操作调用 -
利用 RAII 模式
// 使用包装类自动管理线程生命周期 -
异常安全编程
// 移动赋值不会抛出异常,但后续操作可能抛出 -
避免复杂的线程所有权转移
// 保持线程所有权的清晰和简单
移动赋值运算符使得线程对象可以安全地在不同作用域和容器之间转移,同时保持资源的正确管理,这是现代 C++ 资源管理理念的重要体现。
C++11 std::thread::get_id() 函数
函数声明
std::thread::id get_id() const noexcept;
参数说明
- 无参数
返回值
- 返回
std::thread::id类型的对象,表示线程的唯一标识符 - 如果线程对象不关联任何线程(空线程),返回默认构造的
std::thread::id对象
作用
获取当前线程对象所管理线程的唯一标识符
详细使用示例
1. 基本用法
#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()
#include <iostream>
#include <thread>int main() {// 默认构造的空线程对象std::thread empty_thread;// 获取空线程的IDstd::thread::id empty_id = empty_thread.get_id();std::thread::id default_id; // 默认构造的thread::idstd::cout << "Empty thread ID: " << empty_id << std::endl;std::cout << "Default ID: " << default_id << std::endl;// 比较空线程ID和默认IDif (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的比较和哈希
#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. 实际应用:线程跟踪和调试
#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在性能分析中的应用
#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() 的使用
#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;// 在不同线程中获取当前线程IDstd::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的生命周期
#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(); // 保存线程IDtemp_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的输出格式
#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在容器中的使用
#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));});}// 收集线程IDfor (auto& t : threads) {thread_ids.insert(t.get_id());}// 添加主线程IDthread_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() 函数
函数声明
bool joinable() const noexcept;
参数说明
- 无参数
返回值
- 返回
bool类型:true:线程对象关联着一个可执行线程false:线程对象不关联任何线程或线程不可加入
作用
检查线程对象是否关联着一个活动的、可加入(joinable)的线程
详细使用示例
1. 基本用法和状态检查
#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; // falsestd::cout << "After move - t3 joinable: " << t3.joinable() << std::endl; // trueif (t3.joinable()) {t3.join();}// 情况4: join() 后的线程对象std::cout << "After join - t3 joinable: " << t3.joinable() << std::endl; // falsereturn 0;
}
2. 安全的线程管理模式
#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); // 正常joinSafeThreadManager::safe_join(t1); // 重复join(安全跳过)SafeThreadManager::safe_join(t2); // 空线程(安全跳过)std::thread t3(task);SafeThreadManager::safe_detach(t3); // 正常detachSafeThreadManager::safe_detach(t3); // 重复detach(安全跳过)return 0;
}
3. RAII 线程包装器
#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() 检查
#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. 异常安全的线程处理
#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. 默认构造的线程对象
std::thread t; // 默认构造
std::cout << "Default constructed: " << t.joinable() << std::endl; // false
2. 被移动的线程对象
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() 后的线程对象
std::thread t([]{});
t.join();
std::cout << "After join: " << t.joinable() << std::endl; // false
4. 调用 detach() 后的线程对象
std::thread t([]{});
t.detach();
std::cout << "After detach: " << t.joinable() << std::endl; // false
5. 综合测试
#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()
std::thread t([]{});// 错误:可能抛出 std::system_error
// t.join(); // 如果线程已经结束或不可join,会抛出异常// 正确:先检查
if (t.joinable()) {t.join(); // 安全
}
2. 析构函数的安全性
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. 移动语义的特殊情况
std::thread create_thread() {return std::thread([]{ std::cout << "Temporary thread" << std::endl; });
}int main() {auto t = create_thread(); // 返回值优化,线程仍然joinablestd::cout << "Returned thread joinable: " << t.joinable() << std::endl; // trueif (t.joinable()) {t.join();}return 0;
}
总结
joinable() 函数关键特性
| 特性 | 说明 |
|---|---|
| 函数声明 | bool joinable() const noexcept |
| 参数 | 无 |
| 返回值 | true(可加入)/false(不可加入) |
| 异常安全 | noexcept(不会抛出异常) |
joinable() 返回 false 的情况
- 默认构造的线程对象
- 被移动后的源线程对象
- 调用 join() 后的线程对象
- 调用 detach() 后的线程对象
最佳实践
-
总是先检查 joinable()
if (t.joinable()) {t.join(); // 或 t.detach(); } -
在析构函数中正确处理线程
~MyClass() {if (worker_thread.joinable()) {// 根据需求选择 join() 或 detach()worker_thread.join(); // 或 detach()} } -
使用 RAII 包装器
// 使用 ScopedThread 等包装器自动管理生命周期 -
避免重复操作
// 错误:可能重复join // t.join(); t.join(); // 正确 if (t.joinable()) t.join(); if (t.joinable()) t.join(); // 第二次不会执行
joinable()函数是多线程编程中的安全检查工具,正确使用可以避免程序崩溃和资源泄漏,是编写健壮多线程代码的基础。
C++11 std::thread::join() 函数
函数声明
void join();
参数说明
- 无参数
返回值
- 无返回值(void)
作用
阻塞当前线程,直到被调用的线程对象执行完成
详细使用示例
1. 基本用法和线程同步
#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. 顺序执行控制
#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. 并行执行与结果收集
#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() 使用
#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() {// 测试正常joinstd::thread t1(normal_worker);SafeThreadManager::safe_join(t1);// 测试重复joinstd::cout << "\nTesting duplicate join:" << std::endl;SafeThreadManager::safe_join(t1); // 应该输出"not joinable"// 测试带超时的joinstd::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 线程管理类
#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();}}// 获取线程IDstd::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;// 线程会在作用域结束时自动joinstd::cout << "Leaving scope, threads will auto-join..." << std::endl;}std::cout << "All threads completed automatically" << std::endl;return 0;
}
join() 的错误用法和陷阱
1. 对不可join的线程调用join()
#include <iostream>
#include <thread>
#include <system_error>void demonstrate_join_errors() {std::thread t1; // 默认构造,不可jointry {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. 死锁场景
#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() 的阻塞特性
#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() 与异常安全
#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()
if (t.joinable()) {t.join(); } -
使用 RAII 模式管理线程生命周期
class ScopedThread {std::thread t; public:~ScopedThread() {if (t.joinable()) t.join();}// ... 其他成员函数 }; -
异常安全设计
void safe_function() {std::thread t(worker);ExceptionGuard guard(t); // 确保异常时线程被正确join// 可能抛出异常的操作 } -
避免 join() 的阻塞导致界面冻结
// 在GUI应用中,考虑使用异步操作代替直接join
join()是多线程编程中的基本同步机制,正确使用可以确保线程间的有序执行和资源的安全释放。
C++11 std::thread::detach() 函数详解
函数声明
void detach();
参数说明
- 无参数
返回值
- 无返回值(void)
作用
将线程对象与底层执行线程分离,允许线程独立运行。分离后,线程资源在线程结束时由系统自动回收。
详细使用示例
1. 基本用法和分离线程行为
#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)模式
#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. 日志记录器的分离线程实现
#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. 分离线程的资源管理挑战
#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. 监控和通信模式
#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. 访问已销毁的局部变量
#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 和无效操作
#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;// 错误:重复detachtry {t1.detach(); // 抛出std::system_error} catch (const std::system_error& e) {std::cerr << "Error detaching already-detached thread: " << e.what() << std::endl;}// 错误:对已detach的线程调用jointry {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. 生命周期管理最佳实践
#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. 资源清理模式
#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 管理共享数据
auto data = std::make_shared<MyData>(); std::thread t([data] { /* 安全使用数据 */ }); t.detach(); -
避免捕获局部变量引用
// 危险 std::thread t([&local] { /* 可能访问已销毁对象 */ });// 安全 std::thread t([local] { /* 使用副本 */ }); -
提供监控机制
// 使用atomic变量或promise/future监控状态 std::atomic<bool> completed{false}; std::thread t([&completed] { /* ... */ completed = true; }); t.detach(); -
清晰的资源管理策略
// 确保所有资源都有明确的生命周期管理 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() 函数
函数声明
成员函数版本
void swap(thread& other) noexcept;
非成员函数版本
void swap(thread& lhs, thread& rhs) noexcept;
参数说明
- 成员函数:
other- 要与之交换的另一个线程对象 - 非成员函数:
lhs,rhs- 要交换的两个线程对象
返回值
- 无返回值(void)
作用
交换两个线程对象的所有权,包括它们所管理的底层线程句柄
详细使用示例
1. 基本 swap() 成员函数使用
#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() 使用
#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;// 使用非成员函数swapstd::swap(t1, t2); // 交换t1和t2std::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. 线程排序和优先级管理
#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. 线程池中的线程交换
#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. 异常安全的线程交换
#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的内容移到tempa.swap(b); // b的内容移到ab.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. 实现线程的"移动"语义
#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的内容移动到tempreturn 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. 线程状态跟踪和调试
#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
#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; // falsestd::cout << "t2 ID changed: " << (id2_before != id2_after) << std::endl; // falseif (t1.joinable()) t1.join();if (t2.joinable()) t2.join();
}
2. 自交换安全性
#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()算法
最佳实践
-
优先使用标准算法:
std::swap(t1, t2); // 非成员函数版本 -
确保异常安全:
// swap是noexcept的,但还是要确保资源管理正确 void safe_operation(std::thread& a, std::thread& b) {std::thread temp;temp.swap(a); // 备份atry {a.swap(b); // 主要操作b.swap(temp); // 完成交换} catch (...) {// 异常处理a.swap(temp); // 恢复athrow;} } -
结合RAII模式:
class 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() 函数
函数声明
std::thread::id get_id() noexcept;
参数
- 无参数
返回值
std::thread::id:当前线程的唯一标识符
作用
获取当前执行线程的唯一标识符
使用示例
#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表示"非线程"
使用细节
// 线程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() 函数
函数声明
void yield() noexcept;
参数
- 无参数
返回值
- 无返回值
作用
提示调度器让出当前线程的时间片,允许其他线程运行
使用示例
#include <iostream>
#include <thread>
#include <atomic>
#include <chrono>class SpinLock {
private:std::atomic<bool> locked_{false};public:void lock() {// 自旋锁:使用yield避免忙等待消耗CPUwhile (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(); // 让出CPUlock.lock();}int value = queue_.front();queue_.pop();return value;}
};int main() {demonstrate_yield();return 0;
}
注意事项
- 提示而非强制:
yield()只是建议,调度器可能忽略 - 避免过度使用:不合理的yield可能降低性能
- 替代忙等待:比纯自旋锁更友好
- 不适合精确同步:不能保证特定线程获得执行权
使用细节
// 正确的yield使用模式
while (!condition_met()) {std::this_thread::yield(); // 而不是忙等待
}// 与sleep_for的区别
std::this_thread::yield(); // 立即重新调度
std::this_thread::sleep_for(1ms); // 至少睡眠指定时间
3. sleep_until() 函数
函数声明
template<class Clock, class Duration>
void sleep_until(const std::chrono::time_point<Clock, Duration>& sleep_time);
参数
sleep_time:要阻塞直到达到的时间点
返回值
- 无返回值
作用
阻塞当前线程直到达到指定的时间点
使用示例
#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更适合精确计时
使用细节
// 使用不同的时钟类型
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() 函数
函数声明
template<class Rep, class Period>
void sleep_for(const std::chrono::duration<Rep, Period>& sleep_duration);
参数
sleep_duration:要阻塞的时间长度
返回值
- 无返回值
作用
阻塞当前线程指定的时间长度
使用示例
#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次重试,基础延迟100msint 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资源
使用细节
// 不同的时间单位
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秒
综合应用示例
高级线程调度器
#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秒后执行,优先级10scheduler.schedule([]() {std::cout << "Normal priority task executed" << std::endl;}, 2000, 5); // 2秒后执行,优先级5scheduler.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模式管理线程资源
- 考虑时钟稳定性选择适当的时钟类型
