std::thread非常详细的解释
西笑生 2024-09-12 10:35:01 阅读 66
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 <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: 20
Thread 1 ID: 16628
Thread 2 ID: 9456
Thread 1 is joinable.
Native handle for thread 1: 00000000000000C4
Native handle for thread 2: 00000000000000C8
Swapped thread 3 and 4.
Thread 3 ID after swap: 10992
Thread 4 ID after swap: 22592
Waiting 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: 23612
Thread 2 ID: 2940
Thread 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.
声明
本文内容仅代表作者观点,或转载于其他网站,本站不以此文作为商业用途
如有涉及侵权,请联系本站进行删除
转载本站原创文章,请注明来源及作者。