c++11 thread库

默认分类 · 2024-05-09 · 46 人浏览

C++11引入了强大的线程库 std::thread,相比于Linux下的pthread要方便许多。

头文件

<thread>

使用方法

先来一个示例

#include <thread>
#include <iostream>

using namespace std;

void t() {
    cout << "t() Hello World" << endl;
}

int main() {

    thread t1([]() {
        cout << "lambda Hello World" << endl;
    });
    thread t2(t);

    t1.join();
    t2.join();
}

这段代码的作用就是创建两个线程,并在主线程内等待他们结束
thread这个类的构造函数可以接受一个函数指针或者lambda表达式,当我们thread类的对象创建,就会创建线程来执行我们传入的函数或lambda表达式。这个线程对象也会关联这个线程。
如果要给线程函数传参的话,直接在构造函数中传入就可以了
还是刚才的例子,如果f函数接受一个整型参数,那么这样写就可以了

thread t2(t, num);

如果还需要更多的参数的话,直接接在后边就行了。

在看以下thread的几个成员函数

  • get_id() 获取线程id
  • joinable() 线程是否还在执行,joinable代表的是一个正在执行中的线程。
  • join() 该函数调用后会阻塞住线程,当该线程结束后,主线程继续执行
  • detach() 在创建线程对象后马上调用,用于把被创建线程与线程对象分离开,分离的线程变为后台线程,创建的线程的"死活"就与主线程无关,就算主线程先结束了,对这个后台线程也没有影响。

它没有拷贝构造和拷贝赋值,但是有移动构造和移动赋值,可以将一个线程对象关联的线程转移给另一个线程对象

原子性操作库

C++11中引入了原子操作 atomic。
头文件 <atomic>
通过使用atomic,我们可以在不加锁的情况下,访问临界资源而没有一致性问题
看一个示例

#include <thread>
#include <iostream>


using namespace std;

// int a = 0; 
//如果使用原子操作这样写就可以了
atomic<int> a(0);

void t(int n) {
    for(int i = 0; i < n; i++) {
        a++;
    }
}


int main() {

    thread t1(t, 100000);
    thread t2(t, 100000);
    t1.join();
    t2.join();
    cout << a << endl;
}

  1. 互斥锁(Mutex)
    头文件:< mutex >
    通过构造std::mutex的对象创建互斥锁,调用成员函数lock()来锁定它,调用unlock()来解锁
  2. 条件锁
    头文件:< condition_variable >
    就是条件变量,配合 Mutex使用
  3. lock_guard(守卫锁)
    头文件:< mutex >
    通过构造和析构函数来自动控制加锁解锁
    使用lock_guard<mutex> guard(mtx) 创建守卫锁,他会在作用域内自动给mtx加锁和解锁
  4. recursive_mutex 允许同一个线程对互斥量多次上锁(即递归上锁)
    头文件:< mutex >
Theme Jasmine by Kent Liao