C++ std::thread 线程创建和启动

01

 

引言

std::thread 是C++11标准引入的一个轻量级线程库,它提供了创建和管理线程的能力,方便用户创建新的线程,并执行指定的函数。

 

02

 

使用方法

std::thread 使用很方便,以下是一个简单的示例代码:

  •  
#include #include 
void myTask(int id) {    std::cout << "Thread " << id << " is running" << std::endl;}
int main() {    std::thread t1(myTask, 1);  // 创建一个新线程 t1,执行 myTask 函数,并传递参数 1    std::thread t2(myTask, 2);  // 创建一个新线程 t2,执行 myTask 函数,并传递参数 2
    std::cout << "Main Thread is running" << std::endl;
    t1.join();  // 等待线程 t1 执行完毕    t2.join();  // 等待线程 t2 执行完毕
    std::cout << "All threads are finished" << std::endl;
    return 0;}

results:

Main Thread is running

Thread 1 is running

Thread 2 is running

All threads are finished

 

 

03

 

std::thread 线程创建方法

在 C++ 中,使用标准库的 std::thread 类可以创建和管理线程。以下是创建线程的基本步骤:

  1. 定义线程函数:首先需要定义一个函数,作为线程的入口点。该函数将在新线程中执行。例如:

  •  
void myThreadFunction() {    // 在这里编写线程的逻辑代码}
  1. 创建线程对象并启动线程:使用 std::thread 类创建线程对象,并将线程函数作为参数传递给构造函数。然后,使用线程对象的 join 或 detach 方法。

  •  
int main() {    // 创建线程对象并启动线程    std::thread myThread(myThreadFunction);
    // 执行其他主线程的操作
    // 等待线程结束并回收资源    myThread.join();
    return 0;}

除了 join 方法外,还可以使用 detach 方法分离线程。使用 detach 后,线程将在后台运行,且不能再通过 join 方法等待其结束。这在某些情况下可能会有用,但需要确保线程的资源能够正确管理和释放。

 

 

04

 

std::thread 线程函数参数

在创建 std::thread 对象时,可以向其构造函数传递线程函数的参数。有几种方式可以传递参数:

  1. 使用函数指针或成员函数指针:如果线程函数是一个全局函数、静态成员函数或非静态成员函数,可以直接将函数指针或成员函数指针作为参数传递给 std::thread 构造函数。例如:

  •  
void myThreadFunction(int arg1, double arg2) {    // 在线程函数中使用传递的参数    // TODO: 线程逻辑代码}
class MyClass {public:    void myMemberThreadFunction(int arg1, double arg2) {        // 在成员线程函数中使用传递的参数        // TODO: 线程逻辑代码    }};
int main() {    int arg1 = 42;    double arg2 = 3.14;    std::thread myThread(myThreadFunction, arg1, arg2);
    MyClass obj;    std::thread memberThread(&MyClass::myMemberThreadFunction, &obj, arg1, arg2);
    // 执行其他主线程的操作
    myThread.join();    memberThread.join();
    return 0;}

2. 使用 lambda 表达式:可以使用 lambda 表达式捕获并传递参数。例如:

  •  
int main() {    int arg1 = 42;    double arg2 = 3.14;
    std::thread myThread([&arg1, arg2]() {        // 在线程函数中使用捕获的参数        // TODO: 线程逻辑代码    });
    // 执行其他主线程的操作
    myThread.join();
    return 0;}

lambda 表达式 [&arg1, arg2] 捕获了外部变量 arg1,并通过值传递方式传递了 arg2,然后将 lambda 表达式作为线程函数传递给 std::thread 构造函数。

3. 无论是使用函数指针、成员函数指针还是 lambda 表达式,都可以在创建 std::thread 对象时传递线程函数的参数。这样可以灵活地传递参数给线程函数,并在处理线程时进行更细粒度的控制。

 

 

05

 

std::thread 线程构造函数

以下是 std::thread 构造函数的几种常用形式:

  1. 默认构造函数:创建一个未关联任何线程的 std::thread 对象。

  •  
std::thread t;
  1. 函数构造函数:接受一个可调用对象(如函数、lambda表达式或函数对象)作为参数,创建并启动一个新线程。

  •  
std::thread t(threadFunction);
  1. 参数化函数构造函数:接受一个可调用对象和若干参数,这些参数将被传递给可调用对象。

  •  
std::thread t(threadFunction, arg1, arg2, ...);
  1. 复制构造函数(已删除):std::thread 的复制构造函数被删除,因此不能通过复制来复制线程对象。

  2. 移动构造函数:接受一个 std::thread 对象作为参数,转移线程所有权。

  •  
std::thread t1(threadFunction);std::thread t2 = std::move(t1);
  1. 从 std::thread::id 构造:接受一个 std::thread::id 类型的参数,但通常不直接使用。

  •  
std::thread::id id;std::thread t(id);
  1. 接受现有线程的构造函数:接受一个已经存在的 std::thread 对象,创建一个新的线程对象,两者将共享同一个线程。

  •  
std::thread t1(threadFunction);std::thread t2 = t1; // t2 现在引用 t1 的线程

 

 

06

 

std::thread 线程状态属性

在C++中,std::thread 类并没有直接提供线程状态属性,如线程是否正在运行、阻塞或已完成。然而,你可以使用一些方法来推断线程的状态或与之相关的信息:

  1. joinable()

    joinable成员函数可以用来检查线程是否可加入,即线程是否已经启动且尚未完成。如果线程已经启动且未完成,返回 true;如果线程尚未启动或已经完成,返回 false。

  •  
std::thread t(threadFunction);bool isThreadRunning = t.joinable(); // 检查线程是否可加入
  1. get_id():

    get_id成员函数返回线程的唯一标识符。如果线程未启动或已经结束,返回 std::thread::id()。

  •  
std::thread::id id = t.get_id(); // 获取线程ID
  1. join()

    调用 join() 会等待线程完成。如果线程已经完成,join() 将立即返回。

  •  
t.join(); // 等待线程t完成
  1. detach()

    调用 detach() 会分离线程,使其在后台运行。分离后的线程将无法被 join() 或 cancel()。

  •  
t.detach(); // 线程在后台继续运行
  1. 硬件线程数

    std::thread::hardware_concurrency() 函数可以用来获取系统支持的硬件线程数,这有助于确定并行任务的最佳数量。

  •  
std::thread::hardware_concurrency(); // 获取硬件线程数
  1. 自定义同步机制

    使用 std::mutex、std::condition_variable 或 std::atomic 等同步机制,可以自定义线程状态的检查和控制。

 

 

07

 

小结

​​​​​​​#include #include using namespace std; void foo(int Z) { // 一个虚拟函数 for (int i = 0; i < Z; i++) { cout << "线程使用函数指针作为可调用参数\n"; }} class thread_obj { // 可调用对象public: void operator()(int x) { for (int i = 0; i < x; i++) cout << "线程使用函数对象作为可调用参数\n"; }}; int main() { thread th1(foo, 3); // 函数指针 thread th2(thread_obj(), 3); // 函数对象 auto f = [](int x) { // 定义 Lambda 表达式 for (int i = 0; i < x; i++) cout << "线程使用 lambda 表达式作为可调用参数\n"; }; thread th3(f, 3); // 线程通过使用 lambda 表达式作为可调用的参数 th1.join(); // 等待线程 t1 t2 t3完成 th2.join(); th3.join(); return 0;}

 

 

你可能感兴趣的:(c++)