当前位置:首页 » 《休闲阅读》 » 正文

std::thread非常详细的解释

10 人参与  2024年09月08日 16:43  分类 : 《休闲阅读》  评论

点击全文阅读


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.

点击全文阅读


本文链接:http://zhangshiyu.com/post/157077.html

<< 上一篇 下一篇 >>

  • 评论(0)
  • 赞助本站

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。

关于我们 | 我要投稿 | 免责申明

Copyright © 2020-2022 ZhangShiYu.com Rights Reserved.豫ICP备2022013469号-1