C++ Thead的基本使用

在C++11中,创建线程的基本步骤如下:

  1. 定义线程入口点:需要一个可调用的函数或函数对象作为线程的入口点。

  2. 创建线程对象:使用std::thread类创建线程对象,指定线程入口点和可能的参数。

  3. 传递参数:可以通过函数参数、全局变量、引用等方式向线程传递参数。使用std::ref来包装引用传递的参数。

  4. 等待线程完成:如果需要等待线程完成,使用join()方法等待线程结束,以便获取线程的执行结果或执行清理操作。

一、定义线程入口点

在C++中,定义线程的入口点时,可以使用以下几种方式:

1. 函数指针

可以将一个普通函数作为线程的入口点,例如:

#include <iostream>
#include <thread>

void threadFunction() {
    std::cout << "Hello from thread!" << std::endl;
}

int main() {
    std::thread t(threadFunction);
    t.join();
    return 0;
}

2. Lambda 表达式

可以使用 lambda 表达式作为线程的入口点,例如:

首先简单介绍 lambda 表达式

[capture-list](parameters) -> return-type {  
    // Lambda函数体  
}
  • Capture List(捕获列表):用于捕获Lambda函数体外部的变量,可以是引用捕获或值捕获。
  • Parameters(参数列表):与普通函数类似,指定Lambda函数的参数列表。
  • Return Type(返回类型):指定Lambda函数的返回类型,可以省略,由编译器自动推导。
  • Lambda Body(Lambda函数体):定义Lambda函数的具体实现。

Lambda表达式的使用场景包括但不限于:

  • 简化回调函数的定义。
  • 在算法和标准库函数中作为参数使用,如std::sort
  • 用于并发编程中,例如C++11中的多线程库。

Lambda表达式的优点是可以减少代码量,使代码更具可读性,并且可以轻松地在需要时定义函数,而无需显式命名函数。

#include <iostream>
#include <thread>

int main() {
    std::thread t([](){
        std::cout << "Hello from thread!" << std::endl;
    });
    t.join();
    return 0;
}

3. 函数对象(Functor)

可以定义一个重载了`operator()`的类对象,并将其实例作为线程的入口点,例如:

#include <iostream>
#include <thread>

class ThreadFunctor {
public:
    void operator()() {
        std::cout << "Hello from thread!" << std::endl;
    }
};

int main() {
    ThreadFunctor tf;
    std::thread t(tf);
    t.join();
    return 0;
}

4.一个类的成员函数

当想要在std::thread中调用一个类的成员函数时,通常需要使用成员函数指针,并且需要将对象的指针作为第一个参数传递给std::thread构造函数。通过使用引用符号&来获取成员函数的地址。然后我们传递了obj作为对象指针,要是func()有额外参数再在后边继续写。

#include <iostream>
#include <thread>
#include <memory>

class MyClass {
public:
    void func() {
        std::cout << "Thread " << std::this_thread::get_id() 
        << " started" << std::endl;
        // do some work
        std::cout << "Thread " << std::this_thread::get_id() 
        << " finished" << std::endl;
    }
};

int main() {
    std::shared_ptr<MyClass> obj = std::make_shared<MyClass>();
    std::thread t(&MyClass::func, obj);
    t.join();
    return 0;
}

 这么写std::thread t(MyClass::func, obj);就会报错。

二、创建线程对象 

  • threadFunction是线程的入口点函数,接受一个整数参数。
  • main函数中,定义了一个整数变量param作为要传递给线程的参数。
  • 使用std::thread t(threadFunction, param);创建了一个线程对象t,并将param作为参数传递给线程。
  • 最后使用t.join()等待线程完成
#include <iostream>
#include <thread>

// 线程入口点函数,接受一个整数参数
void threadFunction(int x) {
    std::cout << "Thread function - Received parameter: " << x << std::endl;
}

int main() {
    int param = 42;

    // 创建线程对象,并传递参数
    std::thread t(threadFunction, param);

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

    return 0;
}

三、传递参数 

在C++中,当创建线程并向其传递参数时,可以通过函数参数、全局变量、引用等方式传递参数。使用`std::ref`来包装引用传递的参数可以确保线程函数能够操作原始变量而不是其拷贝。

 1. 通过函数参数传递参数

#include <iostream>
#include <thread>

void threadFunction(int x) {
    std::cout << "Thread function - Received parameter: " << x << std::endl;
}

int main() {
    int param = 42;

    std::thread t(threadFunction, param);
    t.join();

    return 0;
}

在这种方式下,参数`param`会被传递给线程函数`threadFunction`的参数`x`,但是是通过值传递,即线程函数操作的是参数的拷贝。

2. 通过引用传递参数(使用`std::ref`)

#include <iostream>
#include <thread>

void threadFunction(int& x) {
    x = x * 2; // 修改传入的参数
}

int main() {
    int param = 42;

    std::thread t(threadFunction, std::ref(param));
    t.join();

    std::cout << "Updated parameter value after thread execution: " << param << std::endl;

    return 0;
}

在这种方式下,通过`std::ref`包装`param`,确保线程函数`threadFunction`接收到的是`param`的引用,这样线程函数对参数的修改会影响原始变量。

 3. 使用全局变量传递参数

#include <iostream>
#include <thread>

int globalParam = 42;

void threadFunction() {
    std::cout << "Thread function - Received parameter: " << globalParam << std::endl;
}

int main() {
    std::thread t(threadFunction);
    t.join();

    return 0;
}

在这种方式下,线程函数可以直接访问全局变量`globalParam`作为参数,但要注意对全局变量的读写需要考虑线程安全性。

四、等待线程完成

在多线程编程中,通常情况下主线程和子线程是并发执行的,主线程不会等待子线程执行完成就会继续执行。如果主线程需要等待子线程执行完成,可以使用join()方法来等待线程结束。

在C++的std::thread类中,joinable()方法用于检查线程是否可以被join()detach(),返回一个布尔值。如果线程可以被join()detach(),则joinable()返回true,否则返回false

主线程创建了一个线程t,然后通过t.joinable()检查线程是否可以被join()。如果线程可以被join(),则调用t.join()等待线程执行完成;否则输出提示信息。

#include <iostream>
#include <thread>

void threadFunction() {
    // 模拟线程执行一段时间的操作
    std::this_thread::sleep_for(std::chrono::seconds(2));
    std::cout << "Thread execution complete." << std::endl;
}

int main() {
    std::thread t(threadFunction);

    if (t.joinable()) {
        std::cout << "Thread is joinable. Joining the thread..." << std::endl;
        t.join();
    } else {
        std::cout << "Thread is not joinable." << std::endl;
    }

    std::cout << "Main thread continues." << std::endl;

    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

水理璇浮

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

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

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

打赏作者

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

抵扣说明:

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

余额充值