std::thread非常详细的解释
flyfish
在主函数 main 中使用 std::thread 的各个成员函数。这个例子包括了创建线程、获取线程信息、等待线程完成以及释放线程资源。
std::thread 是 C++11 标准库中的一个类,用于支持多线程编程。它提供了一些成员函数来管理线程的生命周期和与线程进行交互。
以下是 std::thread 的一些主要成员函数及其使用方法:
joinable(): 检查线程是否可以被 join。
get_id(): 获取线程的 ID。
native_handle(): 获取与实现相关的本机句柄。
hardware_concurrency(): 返回实现的并发级别(硬件支持的最大并发线程数)。
join(): 阻塞调用线程,直到被调用线程完成。
detach(): 将线程与调用对象分离,允许线程在后台继续运行。
swap(): 交换两个 std::thread 对象的状态。
后面会详细解释
展示一个例子
首先输出了硬件支持的最大并发线程数。然后创建了四个线程,并展示了如何获取它们的 ID、检查它们是否可以被 join、获取它们的 native handle 以及交换线程。最后,我们等待前两个线程结束并把后两个线程设置为脱离状态。
#include <iostream>#include <thread>#include <chrono>// 定义一个简单的函数,线程将执行该函数void my_function(int id) { std::this_thread::sleep_for(std::chrono::seconds(2)); // 模拟耗时操作 std::cout << "Thread " << id << " finished execution." << std::endl;}int main() { // 获取硬件支持的最大并发线程数 std::size_t max_threads = std::thread::hardware_concurrency(); std::cout << "Maximum number of concurrent threads supported by hardware: " << max_threads << std::endl; // 创建多个线程 std::thread t1(my_function, 1); std::thread t2(my_function, 2); // 输出线程的 ID std::cout << "Thread 1 ID: " << t1.get_id() << std::endl; std::cout << "Thread 2 ID: " << t2.get_id() << std::endl; // 检查线程是否可 join if (t1.joinable()) { std::cout << "Thread 1 is joinable." << std::endl; } else { std::cout << "Thread 1 is not joinable." << std::endl; } // 输出底层线程句柄(具体实现依赖于平台) void* handle1 = t1.native_handle(); void* handle2 = t2.native_handle(); std::cout << "Native handle for thread 1: " << handle1 << std::endl; std::cout << "Native handle for thread 2: " << handle2 << std::endl; // 交换线程 std::thread t3(my_function, 3); std::thread t4(my_function, 4); t3.swap(t4); std::cout << "Swapped thread 3 and 4." << std::endl; // 输出交换后的线程 ID std::cout << "Thread 3 ID after swap: " << t3.get_id() << std::endl; std::cout << "Thread 4 ID after swap: " << t4.get_id() << std::endl; // 等待线程 t1 和 t2 结束 std::cout << "Waiting for threads 1 and 2 to finish..." << std::endl; t1.join(); t2.join(); // 设置线程 t3 和 t4 为脱离状态 std::cout << "Detaching threads 3 and 4..." << std::endl; t3.detach(); t4.detach(); std::cout << "Main function completed." << std::endl; return 0;}
输出
Maximum number of concurrent threads supported by hardware: 20Thread 1 ID: 16628Thread 2 ID: 9456Thread 1 is joinable.Native handle for thread 1: 00000000000000C4Native handle for thread 2: 00000000000000C8Swapped thread 3 and 4.Thread 3 ID after swap: 10992Thread 4 ID after swap: 22592Waiting for threads 1 and 2 to finish...Thread 1 finished execution.Thread 4Thread 2 finished execution.Thread 3 finished execution. finished execution.Detaching threads 3 and 4...Main function completed.
join() 说明
join() 方法用于等待线程完成其任务。当调用 join() 方法时,调用线程(通常是主线程)会被阻塞,直到被 join 的线程完成为止。
关于何时线程不可 join,有以下几种情况:
线程尚未启动:
如果线程对象尚未被启动,那么它是不可 join 的。例如,如果创建了一个 std::thread 对象但没有传递任何函数给它,或者还没有调用 start() 方法(注意:std::thread 没有 start() 方法,线程是在构造时立即启动的)。
线程已经结束:
如果线程已经完成了它的任务,并且线程对象已经被 join 或者 detach,那么它是不可 join 的。这是因为线程资源已经被释放。
线程已经被 detach:
如果线程被 detach() 方法分离,那么它将不会被 join。这意味着线程将在完成后自动清理资源,而不需要调用 join() 方法。一旦线程被 detach,它就不再与 std::thread 对象关联,因此也不可再 join。
线程对象已经销毁:
如果 std::thread 对象已经超出作用域并被销毁,那么它是不可 join 的。在这种情况下,线程会被自动 join 或 detach,具体取决于线程的状态。
输出
Thread 1 ID: 23612Thread 2 ID: 2940Thread 1 is joinable.Waiting for threads 1 and 2 to finish...Thread 2 finished execution.Thread 1 finished execution.Threads 1 and 2 have been joined.Thread 3 is not joinable.Thread 4 is not joinable.
detach()说明
detach() 方法用于将线程设置为脱离状态。脱离状态的线程会在完成后自动清理资源,不需要其他线程调用 join() 方法。这在以下场景中是有用的:
后台任务:如果有一些后台任务,如日志记录、数据同步等,这些任务可以在主线程退出后继续运行,这时可以使用 detach() 方法。
非阻塞操作:如果希望主线程不等待子线程完成,而是继续执行其他任务,可以使用 detach()。
线程池:在实现线程池时,通常会将线程设置为脱离状态,以便线程可以自动回收资源。
动态调整线程分配
如何使用 std::thread::swap 方法来动态地重新分配任务到线程。swap 方法确保了线程对象的状态被正确交换,而不需要重新创建或销毁线程
初始化线程池:首先创建了一个包含 numThreads 个线程的向量,并为每个线程分配一个任务。
动态调整线程分配:循环遍历线程池中的每个线程,对于每个线程,等待它完成当前任务后,如果还有新的任务要执行,就创建一个新的线程对象,并使用 swap 方法将新任务移到原来的线程对象上。
确保所有线程完成任务:在完成所有任务调整后,再次循环遍历线程池,确保所有线程都已完成它们的任务。
输出所有任务完成的消息:最后输出一条消息,表示所有任务都已经完成。
#include <iostream>#include <thread>#include <vector>#include <chrono>#include <mutex>std::mutex mtx; // 用于输出的互斥量void taskFunction(int taskID) { std::this_thread::sleep_for(std::chrono::seconds(1)); std::lock_guard<std::mutex> lock(mtx); std::cout << "Task " << taskID << " is complete." << std::endl;}int main() { const int numThreads = 4; std::vector<std::thread> threadPool(numThreads); // 启动初始任务 for (int i = 0; i < numThreads; ++i) { threadPool[i] = std::thread(taskFunction, i + 1); } // 动态调整线程分配 for (int i = 0; i < numThreads; ++i) { if (threadPool[i].joinable()) { // 等待当前线程完成任务 threadPool[i].join(); // 如果还有新的任务,将任务移动到该线程上 if (i + numThreads < 2 * numThreads) { std::thread newThread(taskFunction, i + numThreads + 1); // 确保新线程已经启动 newThread.swap(threadPool[i]); } } } // 确保所有线程完成任务 for (int i = 0; i < numThreads; ++i) { if (threadPool[i].joinable()) { threadPool[i].join(); } } std::cout << "All tasks are complete." << std::endl; return 0;}
输出
Task 1 is complete.Task 2 is complete.Task 3 is complete.Task 4 is complete.Task 7 is complete.Task 8 is complete.Task 6 is complete.Task 5 is complete.All tasks are complete.