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 以及交换线程。最后,我们等待前两个线程结束并把后两个线程设置为脱离状态。

<code>#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.



声明

本文内容仅代表作者观点,或转载于其他网站,本站不以此文作为商业用途
如有涉及侵权,请联系本站进行删除
转载本站原创文章,请注明来源及作者。