Apollo  6.0
Open source self driving car software
atomic_rw_lock.h
Go to the documentation of this file.
1 /******************************************************************************
2  * Copyright 2018 The Apollo Authors. All Rights Reserved.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *****************************************************************************/
16 
17 #ifndef CYBER_BASE_ATOMIC_RW_LOCK_H_
18 #define CYBER_BASE_ATOMIC_RW_LOCK_H_
19 
20 #include <unistd.h>
21 
22 #include <atomic>
23 #include <condition_variable>
24 #include <cstdint>
25 #include <cstdlib>
26 #include <iostream>
27 #include <mutex>
28 #include <thread>
29 
31 
32 namespace apollo {
33 namespace cyber {
34 namespace base {
35 
36 class AtomicRWLock {
37  friend class ReadLockGuard<AtomicRWLock>;
39 
40  public:
41  static const int32_t RW_LOCK_FREE = 0;
42  static const int32_t WRITE_EXCLUSIVE = -1;
43  static const uint32_t MAX_RETRY_TIMES = 5;
45  explicit AtomicRWLock(bool write_first) : write_first_(write_first) {}
46 
47  private:
48  // all these function only can used by ReadLockGuard/WriteLockGuard;
49  void ReadLock();
50  void WriteLock();
51 
52  void ReadUnlock();
53  void WriteUnlock();
54 
55  AtomicRWLock(const AtomicRWLock&) = delete;
56  AtomicRWLock& operator=(const AtomicRWLock&) = delete;
57  std::atomic<uint32_t> write_lock_wait_num_ = {0};
58  std::atomic<int32_t> lock_num_ = {0};
59  bool write_first_ = true;
60 };
61 
62 inline void AtomicRWLock::ReadLock() {
63  uint32_t retry_times = 0;
64  int32_t lock_num = lock_num_.load();
65  if (write_first_) {
66  do {
67  while (lock_num < RW_LOCK_FREE || write_lock_wait_num_.load() > 0) {
68  if (++retry_times == MAX_RETRY_TIMES) {
69  // saving cpu
70  std::this_thread::yield();
71  retry_times = 0;
72  }
73  lock_num = lock_num_.load();
74  }
75  } while (!lock_num_.compare_exchange_weak(lock_num, lock_num + 1,
76  std::memory_order_acq_rel,
77  std::memory_order_relaxed));
78  } else {
79  do {
80  while (lock_num < RW_LOCK_FREE) {
81  if (++retry_times == MAX_RETRY_TIMES) {
82  // saving cpu
83  std::this_thread::yield();
84  retry_times = 0;
85  }
86  lock_num = lock_num_.load();
87  }
88  } while (!lock_num_.compare_exchange_weak(lock_num, lock_num + 1,
89  std::memory_order_acq_rel,
90  std::memory_order_relaxed));
91  }
92 }
93 
94 inline void AtomicRWLock::WriteLock() {
95  int32_t rw_lock_free = RW_LOCK_FREE;
96  uint32_t retry_times = 0;
97  write_lock_wait_num_.fetch_add(1);
98  while (!lock_num_.compare_exchange_weak(rw_lock_free, WRITE_EXCLUSIVE,
99  std::memory_order_acq_rel,
100  std::memory_order_relaxed)) {
101  // rw_lock_free will change after CAS fail, so init agin
102  rw_lock_free = RW_LOCK_FREE;
103  if (++retry_times == MAX_RETRY_TIMES) {
104  // saving cpu
105  std::this_thread::yield();
106  retry_times = 0;
107  }
108  }
109  write_lock_wait_num_.fetch_sub(1);
110 }
111 
112 inline void AtomicRWLock::ReadUnlock() { lock_num_.fetch_sub(1); }
113 
114 inline void AtomicRWLock::WriteUnlock() { lock_num_.fetch_add(1); }
115 
116 } // namespace base
117 } // namespace cyber
118 } // namespace apollo
119 
120 #endif // CYBER_BASE_ATOMIC_RW_LOCK_H_
static const int32_t WRITE_EXCLUSIVE
Definition: atomic_rw_lock.h:42
PlanningContext is the runtime context in planning. It is persistent across multiple frames...
Definition: atomic_hash_map.h:25
Definition: rw_lock_guard.h:48
Definition: atomic_rw_lock.h:36
Definition: rw_lock_guard.h:35
AtomicRWLock()
Definition: atomic_rw_lock.h:44
AtomicRWLock(bool write_first)
Definition: atomic_rw_lock.h:45
static const uint32_t MAX_RETRY_TIMES
Definition: atomic_rw_lock.h:43
static const int32_t RW_LOCK_FREE
Definition: atomic_rw_lock.h:41