C++ std::lock_guard
700 Words|Read in about 4 Min|本文总阅读量次
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具有两种构造方法
lock_guard(mutex& m)
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