Tags: C/C++

在看ORB-SLAM代码的时候,经常会遇到unique_lock<mutex>这种代码,这是C++中多线程编程中线程独占锁的概念,本篇博客主要对其进行简单学习。

1.CMake文件需要增加的内容

在CMake文件中需要设置一下CMake的FLAG,具体来说是pthread。一个完整CMake文件写法如下,以供参考:

cmake_minimum_required(VERSION 3.15)
project(learnThread)

set(CMAKE_CXX_STANDARD 11)

# 增加FLAG以启用多线程功能
#set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -pthread")

# 如果需要调试再加几个参数
 set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -pthread -g -march=native")

# 由于会生成多个可执行文件,所以就添加了多个
add_executable(demo1 demo1.cpp)
add_executable(demo2 demo2.cpp)

2.最简单的线程使用

要使用多线程,最基本需要包含thread.h头文件。新建线程并运行的最简单方法如下所示:

#include <iostream>
#include <unistd.h> // Linux系统下的头文件,下面用到的sleep函数就是出自这里,其本身与多线程没什么关系
#include <thread>   // C++多线程API头文件


using namespace std;

// 不带参数的线程函数
void demo1_thread1() {
    while (true) {
        sleep(1);
        cout << "hello world" << endl;
    }
}

// 传入参数的线程函数
void demo1_thread2(int n) {
    while (true) {
        sleep(1);
        cout << "input parameter " << n << endl;
    }
}

int main() {
    int a = 1;
    // 新建两个thread对象
    thread t1(&demo1_thread1);    // 不带参数
    thread t2(&demo1_thread2, a); // 带参数
    // 调用thread对象的成员函数join实现运行
    t1.join();
    t2.join();
    return 0;
}

3.线程同步锁unique_lock的使用

在多线程中经常会遇到多个线程同时修改同一个变量的情况,这个时候如果不对线程进行一定约束,很可能会导致意想不到的结果。例如有两个线程1和线程2,线程2的输入是线程1的结果。很显然如果在主线程中同时开启了线程1和线程2,像上面那样,它们是同时运行的,会直接导致程序的崩溃。所以线程同步锁应运而生,当遇到它时它会让当前线程独占某个变量,其它同样需要修改该变量的线程此时只能处于等待状态,等到当前线程结束之后,线程独占锁自动释放,其它线程可以修改内容。示例如下。

#include <iostream>
#include <unistd.h> // Linux系统下的头文件,下面用到的sleep函数就是出自这里,其本身与多线程没什么关系
#include <thread>   // C++多线程API头文件
#include <mutex>
#include <vector>


using namespace std;

vector<int> vec_int;
// mutex类型的独占锁
std::mutex mymutex;

void demo2_thread1() {
    // 在线程函数执行前加上这一句
    unique_lock<mutex> lock(mymutex);
    for (int i = 0; i < 5; ++i) {
        cout << "Adding element " << i << " from thread 1" << endl;
        vec_int.push_back(i);
        sleep(1);
    }
}

void demo2_thread2() {
    // 在线程函数执行前加上这一句
    unique_lock<mutex> lock(mymutex);
    for (int i = 0; i < 5; ++i) {
        int e = 100 * i + 100;
        cout << "Adding element " << e << " from thread 2" << endl;
        vec_int.push_back(e);
        sleep(1);
    }
}

int main() {
    thread t1(&demo2_thread1);
    thread t2(&demo2_thread2);
    t1.join();
    t2.join();

    for (size_t i = 0; i < vec_int.size(); ++i) {
        cout << "element " << i << " " << vec_int[i] << endl;
    }
    return 0;
}

上面程序的两个线程分别向同一个vector中添加元素,如果没有线程独占锁的保障,会导致添加的元素是乱序的。增加了独占锁以后,输出结果如下。 同时,作为对比,没有添加独占锁的运行结果如下: 可以看到元素是乱序的。

所有示例代码放到了Github上,点击查看

4.参考资料

  • [1]https://blog.csdn.net/coolwriter/article/details/79883253

本文作者原创,未经许可不得转载,谢谢配合

返回顶部