std::thread非常详细的解释

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: 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.
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

西笑生

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值