DUDS
Distributed Update of Data from Something
Spinlock.hpp
Go to the documentation of this file.
1 /*
2  * This file is part of the DUDS project. It is subject to the BSD-style
3  * license terms in the LICENSE file found in the top-level directory of this
4  * distribution and at https://github.com/jjackowski/duds/blob/master/LICENSE.
5  * No part of DUDS, including this file, may be copied, modified, propagated,
6  * or distributed except according to the terms contained in the LICENSE file.
7  *
8  * Copyright (C) 2017 Jeff Jackowski
9  */
10 #ifndef SPINLOCK_HPP
11 #define SPINLOCK_HPP
12 
13 #include <atomic>
14 #include <thread>
15 #include <mutex>
16 #include <boost/noncopyable.hpp>
17 
18 namespace duds { namespace general {
19 
52 class Spinlock : boost::noncopyable {
57  std::atomic_flag af;
62  static bool useYield;
63 public:
68  // staring from unknown state
69  unlock();
70  // state now unlocked
71  }
77  // avoid destruction while in use
78  lock();
79  }
86  void lockNeverYield() {
87  // spiny wait
88  while (af.test_and_set(std::memory_order_acquire)) { }
89  }
98  void lockAlwaysYield() {
99  // not-so-spiny wait
100  while (af.test_and_set(std::memory_order_acquire)) {
101  std::this_thread::yield();
102  }
103  }
109  void lock() {
110  if (useYield) {
111  lockAlwaysYield();
112  } else {
113  lockNeverYield();
114  }
115  }
121  bool try_lock() {
122  // non-spiny wait
123  return !af.test_and_set(std::memory_order_acquire);
124  }
131  template <class Clock, class Duration>
132  bool tryLockNeverYeildUntil(const std::chrono::time_point<Clock,Duration> &time) {
133  bool res;
134  // spiny wait
135  while ((res = af.test_and_set(std::memory_order_acquire)) &&
136  (time <= std::chrono::time_point<Clock,Duration>::now())
137  ) { }
138  return !res;
139  }
146  template <class Clock, class Duration>
147  bool tryLockAlwaysYeildUntil(const std::chrono::time_point<Clock,Duration> &time) {
148  bool res;
149  // not-so-spiny wait
150  while ((res = af.test_and_set(std::memory_order_acquire)) &&
151  (time <= std::chrono::time_point<Clock,Duration>::clock::now())
152  ) {
153  std::this_thread::yield();
154  }
155  return !res;
156  }
163  template <class Clock, class Duration>
164  bool try_lock_until(const std::chrono::time_point<Clock,Duration> &time) {
165  if (useYield) {
166  return tryLockAlwaysYeildUntil(time);
167  } else {
168  return tryLockNeverYeildUntil(time);
169  }
170  }
177  template <class Rep, class Period>
178  bool tryLockNeverYeildFor(const std::chrono::duration<Rep,Period> &duration) {
179  return tryLockNeverYeildUntil(std::chrono::steady_clock::now() + duration);
180  }
187  template <class Rep, class Period>
188  bool tryLockAlwaysYeildFor(const std::chrono::duration<Rep,Period> &duration) {
189  return tryLockAlwaysYeildUntil(std::chrono::steady_clock::now() + duration);
190  }
197  template <class Rep, class Period>
198  bool try_lock_for(const std::chrono::duration<Rep,Period> &duration) {
199  if (useYield) {
200  return tryLockAlwaysYeildFor(duration);
201  } else {
202  return tryLockNeverYeildFor(duration);
203  }
204  }
208  void unlock() {
209  af.clear(std::memory_order_release);
210  }
211 };
212 
216 typedef std::lock_guard<duds::general::Spinlock> SpinLockGuard;
217 
221 typedef std::unique_lock<duds::general::Spinlock> UniqueSpinLock;
222 
223 
245 class SpinlockYieldingWrapper : boost::noncopyable {
247 public:
249  void lock() {
250  sl.lockAlwaysYield();
251  }
252  bool try_lock() {
253  return sl.try_lock();
254  }
255  template <class Clock, class Duration>
256  bool try_lock_until(const std::chrono::time_point<Clock,Duration> &time) {
257  return sl.tryLockAlwaysYeildUntil(time);
258  }
259  template <class Rep, class Period>
260  bool try_lock_for(const std::chrono::duration<Rep,Period> &duration) {
261  return sl.tryLockAlwaysYeildFor(duration);
262  }
263  void unlock() {
264  sl.unlock();
265  }
266 };
267 
272 typedef std::lock_guard<duds::general::SpinlockYieldingWrapper>
274 
279 typedef std::unique_lock<duds::general::SpinlockYieldingWrapper>
281 
282 } }
283 
284 #endif // #ifndef SPINLOCK_HPP
bool try_lock()
A single attempt at gaining ownership of the lock.
Definition: Spinlock.hpp:121
void lockAlwaysYield()
A yielding wait that ends with ownership of the lock.
Definition: Spinlock.hpp:98
bool try_lock_until(const std::chrono::time_point< Clock, Duration > &time)
A spiny busy wait or a yielding wait that ends with ownership of the lock if ownership can be granted...
Definition: Spinlock.hpp:164
std::unique_lock< duds::general::Spinlock > UniqueSpinLock
A convenience typedef for a std::unique_lock using the Spinlock object.
Definition: Spinlock.hpp:221
void lock()
A spiny busy or yielding wait that ends with ownership of the lock.
Definition: Spinlock.hpp:109
A simple wrapper around a Spinlock object that implements the timed lockable concept such that attemp...
Definition: Spinlock.hpp:245
std::unique_lock< duds::general::SpinlockYieldingWrapper > UniqueYieldingSpinLock
A convenience typedef for a std::unique_lock using the Spinlock yielding wrapper. ...
Definition: Spinlock.hpp:280
bool tryLockAlwaysYeildFor(const std::chrono::duration< Rep, Period > &duration)
A yielding wait that ends with ownership of the lock if ownership can be granted within duration...
Definition: Spinlock.hpp:188
bool tryLockAlwaysYeildUntil(const std::chrono::time_point< Clock, Duration > &time)
A yielding wait that ends with ownership of the lock if ownership can be granted before time...
Definition: Spinlock.hpp:147
void lockNeverYield()
A spiny busy wait that ends with ownership of the lock.
Definition: Spinlock.hpp:86
~Spinlock()
Locks the spinlock before destruction to delay destruction in case of a lock.
Definition: Spinlock.hpp:76
void unlock()
Releases ownership of the lock.
Definition: Spinlock.hpp:208
std::atomic_flag af
Used like a mutually exclusive semaphore, but doesn&#39;t involve the operating system.
Definition: Spinlock.hpp:57
static bool useYield
True when lock() should call yield in its loop; good for uniprocessor, unicore systems.
Definition: Spinlock.hpp:62
A simple spinlock following the lockable and timed lockable concepts so that it can be used with std:...
Definition: Spinlock.hpp:52
Spinlock()
Makes a Spinlock in the unlocked state.
Definition: Spinlock.hpp:67
bool tryLockNeverYeildFor(const std::chrono::duration< Rep, Period > &duration)
A spiny busy wait that ends with ownership of the lock if ownership can be granted within duration...
Definition: Spinlock.hpp:178
bool try_lock_for(const std::chrono::duration< Rep, Period > &duration)
Definition: Spinlock.hpp:260
bool try_lock_until(const std::chrono::time_point< Clock, Duration > &time)
Definition: Spinlock.hpp:256
bool tryLockNeverYeildUntil(const std::chrono::time_point< Clock, Duration > &time)
A spiny busy wait that ends with ownership of the lock if ownership can be granted before time...
Definition: Spinlock.hpp:132
std::lock_guard< duds::general::SpinlockYieldingWrapper > YieldingSpinLockGuard
A convenience typedef for a std::lock_guard using the Spinlock yielding wrapper.
Definition: Spinlock.hpp:273
bool try_lock_for(const std::chrono::duration< Rep, Period > &duration)
A spiny busy wait or yielding wait that ends with ownership of the lock if ownership can be granted w...
Definition: Spinlock.hpp:198
std::lock_guard< duds::general::Spinlock > SpinLockGuard
A convenience typedef for a std::lock_guard using the Spinlock object.
Definition: Spinlock.hpp:216