Android源码中有一些经常会遇到的c++基础的内容,笔者对C++ std::lock_guard进行简单熟悉。

C++ std::lock_guard

在Android源码中,经常会遇到std::lock_guard这个锁的用法。

 1//system/core/init/init.cpp
 2static class PropWaiterState {
 3  public:
 4    bool StartWaiting(const char* name, const char* value) {
 5        auto lock = std::lock_guard{lock_};
 6        if (waiting_for_prop_) {
 7            return false;
 8        }
 9        if (GetProperty(name, "") != value) {
10            // Current property value is not equal to expected value
11            wait_prop_name_ = name;
12            wait_prop_value_ = value;
13            waiting_for_prop_.reset(new Timer());
14        } else {
15            LOG(INFO) << "start_waiting_for_property(\"" << name << "\", \"" << value
16                      << "\"): already set";
17        }
18        return true;
19    }
20
21    void ResetWaitForProp() {
22        auto lock = std::lock_guard{lock_};
23        ResetWaitForPropLocked();
24    }
25
26    void CheckAndResetWait(const std::string& name, const std::string& value) {
27        auto lock = std::lock_guard{lock_};
28        if (name == kColdBootDoneProp) {
29            auto time_waited = waiting_for_prop_ ? waiting_for_prop_->duration().count() : 0;
30            std::thread([time_waited] {
31                SetProperty("ro.boottime.init.cold_boot_wait", std::to_string(time_waited));
32            }).detach();
33        }
34
35        if (waiting_for_prop_) {
36            if (wait_prop_name_ == name && wait_prop_value_ == value) {
37                LOG(INFO) << "Wait for property '" << wait_prop_name_ << "=" << wait_prop_value_
38                          << "' took " << *waiting_for_prop_;
39                ResetWaitForPropLocked();
40                WakeMainInitThread();
41            }
42        }
43    }
44
45    bool MightBeWaiting() {
46        auto lock = std::lock_guard{lock_};
47        return static_cast<bool>(waiting_for_prop_);
48    }
49
50  private:
51    void ResetWaitForPropLocked() {
52        wait_prop_name_.clear();
53        wait_prop_value_.clear();
54        waiting_for_prop_.reset();
55    }
56
57    std::mutex lock_;
58    std::unique_ptr<Timer> waiting_for_prop_{nullptr};
59    std::string wait_prop_name_;
60    std::string wait_prop_value_;
61
62} prop_waiter_state;

可以看到一个简单的类中,公有函数内部都有这种std::lock_guard的写法。

1lock_guard

lock_guard是一种在作用域内控制可锁对象所有权的类型。

An object of type lock_guard controls the ownership of a lockable object within a scope.

直接查看源码,可以得知实际上lock_guard作用是在lock_guard实例化对象构造的时候会持有对应的锁,而且这个锁是传入锁的别名,即是同一把锁。然后我这个lock_guard实例化对象析构的时候,对先前持有的锁进行释放

 1//std_mutex.h
 2constexpr adopt_lock_t	adopt_lock { };
 3
 4template<typename _Mutex>
 5class lock_guard
 6{
 7    public:
 8    typedef _Mutex mutex_type;
 9    //持有锁
10    explicit lock_guard(mutex_type& __m) : _M_device(__m)
11    { _M_device.lock(); }
12    //这个构造有两个参数,有adopt_lock参数,构造时不加锁
13    lock_guard(mutex_type& __m, adopt_lock_t) noexcept : _M_device(__m)
14    { } // 调用线程拥有互斥锁
15    //释放锁
16    ~lock_guard()
17    { _M_device.unlock(); }
18    //屏蔽拷贝构造
19    lock_guard(const lock_guard&) = delete;
20    lock_guard& operator=(const lock_guard&) = delete;
21
22    private:
23    mutex_type&  _M_device;
24};

2使用方式

lock_guard具有两种构造方法

  1. lock_guard(mutex& m)
  2. lock_guard(mutex& m, adopt_lock)

其中mutex& m是互斥量,参数adopt_lock表示假定调用线程已经获得互斥体所有权并对其进行管理了。

lock_guard的析构方式,只要退出所定义的作用域,这个lock_guard的实例化就会调用内部析构,释放当前的锁。

 1#include <iostream>
 2#include <vector>
 3#include <mutex>
 4#include <string>
 5#include <thread>
 6#include <cstring>
 7
 8using namespace std;
 9#define N 10
10// 时间模拟消息
11bool g_flag = true;
12string mock_msg()
13{
14    char tmp[128];
15    memset(tmp, 0x0, sizeof(tmp));
16    static int i = N;
17    if(i == 0)
18    {
19        g_flag = false;
20    }
21    cout << "buff " << i-- << endl;
22    snprintf(tmp, sizeof(tmp), "buff(%d)", i + 1);
23    return tmp;
24}
25
26class lockGuardTest
27{
28public:
29    void recv_msg(); 			//接收消息
30    void read_msg(); 			//处理消息
31private:
32    vector<string> msg_queue; 	//消息队列
33    mutex m_mutex;				//互斥量
34};
35
36// 模拟接收消息
37void lockGuardTest::recv_msg()
38{
39    while (g_flag)
40    {
41        string msg = mock_msg();
42        cout << "recv the msg " << msg << endl;
43
44        // 这个括号就是lock_guard实例化mylockguard的作用域,出了作用域就会调用析构
45        {
46            lock_guard<mutex> mylockguard(m_mutex);
47            // 消息添加到队列
48            msg_queue.emplace_back(msg);
49        }
50        this_thread::sleep_for(chrono::milliseconds(10));//方便观察数据
51    }
52}
53
54// 模拟读取处理
55void lockGuardTest::read_msg()
56{
57    while (g_flag)
58    {
59        // 已经加锁,这个是采用直接加锁的方式
60        m_mutex.lock();
61        // 使用双参数构造lock_guard实例化mylockguard,其中传入adopt_lock就为第二种构造方式
62        //且adopt_lock是std_mutex.h头文件默认定义的
63        lock_guard<mutex> mylockguard(m_mutex, adopt_lock);
64        if (!msg_queue.empty())
65        {
66            string msg = msg_queue.front();
67            cout << "read the msg " << msg << endl;
68            msg_queue.erase(msg_queue.begin());
69        }
70        this_thread::sleep_for(chrono::milliseconds(10));//方便观察数据
71    }
72}
73
74int main()
75{
76    lockGuardTest test1;
77    thread recv_thread(&lockGuardTest::recv_msg, &test1); //接收线程
78    thread read_thread(&lockGuardTest::read_msg, &test1); //处理线程
79    //等待线程,知道退出
80    recv_thread.join();
81    read_thread.join();
82}

输出结果

 1buff 10
 2recv the msg buff(10)
 3read the msg buff(10)
 4buff 9
 5recv the msg buff(9)
 6read the msg buff(9)
 7buff 8
 8recv the msg buff(8)
 9read the msg buff(8)
10buff 7
11recv the msg buff(7)
12read the msg buff(7)
13buff 6
14recv the msg buff(6)
15read the msg buff(6)
16buff 5
17recv the msg buff(5)
18read the msg buff(5)
19buff 4
20recv the msg buff(4)
21read the msg buff(4)
22buff 3
23recv the msg buff(3)
24read the msg buff(3)
25buff 2
26recv the msg buff(2)
27read the msg buff(2)
28buff 1
29recv the msg buff(1)
30read the msg buff(1)
31buff 0
32recv the msg buff(0)
33
34Process finished with exit code 0