C++11多线程1

172 阅读4分钟

一、线程池thread

std::thread 在#include < thread > 头文件中声明。

进程:就是运行中的程序
线程:就是进程中的进程

1.1、语法

1.1.1、构造函数

  • 默认构造函数
std::thread() noexcept;
  • 初始化构造函数
    初始化构造函数创建一个新的线程,并将该线程与一个可调用对象(如函数、Lambda 表达式、函数对象等)关联。
    • f:可调用对象(函数、Lambda 表达式、函数对象等)。
    • args:传递给可调用对象的参数。
template <class Function, class... Args>
explicit thread(Function&& f, Args&&... args);
  • 拷贝构造函数
//拷贝构造函数(被禁用),意味着不可被拷贝构造
thread(const thread&)=delete;
//所以不能写成
thread t1;
thread t2 = t1;//错误
  • move构造函数
//move构造函数,调用成功之后x不代表任何thread执行对象
注意:可被jionable的thread对象必须在他们销毁之前被主线程join或者将其设置为detached。
thread(thread&& x)noexcept;
thread t1;
thread t2 = move(t1);//正确

1.1.2主要成员函数

join()

join:等待线程执行完毕后返回。
首先看下面例子:

void printHelloWorld()
{
    cout<<"Hello World"<<endl;
}
int main()
{
    thread thread1(printHelloWorld);
    //如果不使用thread1.join();
    //程序是按单线程,从上到下走的,
    //当走到thread时,thread里面肯定需要运行,
    //但是主程序不在意他,继续向下走,就导致
    //报错。因为主程序走完了,但是thread1可能没有走完。
    thread1.join();
    return 0;
}
joinable()

joinable:判断线程是否可以加入等待。

getid()

getid:获取线程ID,返回类型std::thread::id对象

detach()

detach:detach调用之后,目标线程就成为了守护线程,驻留后台运行,与之相关的std::thread对象失去目标线程的关联,无法再通过std::thread对象取得该线程的控制权(例如join)。当线程执行完之后,线程就结束了,运行时库负责清理与该线程的资源。它可能带来崩溃,谨慎使用

detach() 是 C++ 标准库中 std::thread 类的一个成员函数,用于将线程与其创建的 std::thread 对象分离。分离后的线程会独立运行,不再与 std::thread 对象关联。分离后的线程也称为守护线程

  • 调用detach之后:
    • *this不再代表任何线程执行实例。
    • joinable==false
    • get_id()==std::thread::id()

1.1.2、简单线程的创建

  1. 传入0个值
  2. 传入2个值
  3. 传入引用(std::ref())
  4. 传入类函数
  5. detach
  6. move
void printHelloWorld()
{
    cout<<"Hello World"<<endl;
}
int main()
{
    //1.
    thread thread1(printHelloWorld);
    thread1.join();
    return 0;
}
void func2(int a,int b){
    cout<<a+b<<endl;
}
int main()
{
    //2.
    int a = 10;
    int b =20;
    thread thread2(func2,a,b);
    thread2.join();
    return 0;
}
void func3(int &c){
    c+=10;
}

int main()
{
    //3.
    int c =10;
    thread thread3(func3,std::ref(c));
    thread3.join();
    cout<<c<<endl;//20
    return 0;
}
class A{
public:
    //4.类函数
    void func4(int a){
        cout<<"thread:"<<name_<<",fun4 a= "<<a<<endl;
    }
    void setName(string name){
        name_ = name;
    }
    void displayName(){
        cout<<"this:"<<this<<endl;
    }
    void play(){
        cout<<"play call!"<<endl;
    }
private:
    string name_;
};

int main()
{
    //4.
    A* a4_ptr = new A();
    a4_ptr->setName("darren");
    thread thread4(&A::func4,a4_ptr,100);
    thread4.join();
    delete a4_ptr;
    return 0;
}
//5.detach
void func5(){
    this_thread::sleep_for(std::chrono::seconds(1));
    cout<<"func5 leave"<<endl;
}
int main()
{
    //5.

    thread thread5(&func5);
    thread5.detach();//脱离

    return 0;
}
//6.move
void func6(){
    this_thread::sleep_for(std::chrono::seconds(1));
    cout<<"func5 leave"<<endl;
}
int main()
{
    //6.
    int x = 10;
    thread thread6(&func6);
    thread thread7(std::move(thread6));//thread6将线程失去所有权
    thread6.join();//掏出异常
    thread7.join();

    return 0;
}

1.1.3、线程封装

封装线程,子类可以继承,然后子类能实现具体的业务处理逻辑。

1.1.4、this_thread::

this_thread 是 C++ 标准库中的一个命名空间,提供了一些与当前线程相关的工具函数。它定义在 <thread> 头文件中,主要用于操作当前线程的行为,例如让当前线程休眠、获取线程 ID 等。

1. this_thread::get_id()
  • 获取当前线程的唯一标识符(std::thread::id 类型)。
  • 每个线程都有一个唯一的 ID,可以用来区分不同的线程。
#include <iostream>
#include <thread>
using namespace std;

void printThreadId() {
    cout << "Current thread ID: " << this_thread::get_id() << endl;
}

int main() {
    thread t(printThreadId);
    cout << "Main thread ID: " << this_thread::get_id() << endl;
    t.join();
    return 0;
}
2. this_thread::sleep_for()
  • 让当前线程休眠一段指定的时间。
  • 参数是一个时间间隔,通常使用 std::chrono::duration 表示.
#include <iostream>
#include <thread>
#include <chrono>
using namespace std;
int main() {
    cout << "Sleeping for 2 seconds..." << endl;
    this_thread::sleep_for(chrono::seconds(2)); // 休眠 2 秒
    cout << "Awake!" << endl;
    return 0;
}
3. this_thread::sleep_until()
  • 让当前线程休眠直到某个时间点。
  • 参数是一个时间点,通常使用 std::chrono::time_point 表示。
#include <iostream>
#include <thread>
#include <chrono>
using namespace std;

int main() {
    auto wakeupTime = chrono::steady_clock::now() + chrono::seconds(3); // 3 秒后
    cout << "Sleeping until 3 seconds later..." << endl;
    this_thread::sleep_until(wakeupTime); // 休眠到指定时间点
    cout << "Awake!" << endl;
    return 0;
}
4. this_thread::yield()
  • 让当前线程主动放弃 CPU 时间片,让其他线程有机会运行。
  • 通常用于忙等待(busy-wait)场景,避免浪费 CPU 资源。
#include <iostream>
#include <thread>
#include <atomic>
using namespace std;

atomic<bool> ready(false);

void waitForReady() {
    while (!ready) {
        this_thread::yield(); // 让出 CPU 时间片
    }
    cout << "Ready!" << endl;
}

int main() {
    thread t(waitForReady);
    this_thread::sleep_for(chrono::seconds(1)); // 模拟准备工作
    ready = true;
    t.join();
    return 0;
}