blob: 5ed14055c1280bdffc4ac683b56a8d1758b4d137 [file] [log] [blame]
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
**/
#ifndef QUICKSTEP_THREADING_SPIN_MUTEX_HPP_
#define QUICKSTEP_THREADING_SPIN_MUTEX_HPP_
#include <atomic>
#include "threading/Mutex.hpp"
#include "utility/Macros.hpp"
namespace quickstep {
/** \addtogroup Threading
* @{
*/
/**
* @brief Mutex implementation as a pure user-space spinlock. May be more
* efficient than an ordinary Mutex if locks are usually held briefly.
*
* @note Unlike a regular Mutex, SpinMutex can not create condition variables.
* @note In some cases, SpinMutex will perform better if it is aligned on its
* own cache line to avoid false sharing.
**/
class SpinMutex {
public:
SpinMutex() : locked_(false) {
}
/**
* @note This call does NOT yield when contended. SpinMutex is intended
* mainly for cases where locks are held briefly and it is better to
* simply spin for a short time rather than involving the kernel's
* scheduler. Otherwise, a regular Mutex (using the futex mechanism on
* Linux) is a more appropriate choice.
**/
inline void lock() {
bool previous_locked = false;
while (!locked_.compare_exchange_weak(previous_locked,
true,
std::memory_order_acquire,
std::memory_order_relaxed)) {
previous_locked = false;
}
}
inline void unlock() {
locked_.store(false, std::memory_order_release);
}
private:
std::atomic<bool> locked_;
DISALLOW_COPY_AND_ASSIGN(SpinMutex);
};
typedef MutexLockImpl<SpinMutex, true> SpinMutexLock;
template <bool actually_lock> using StaticConditionalSpinMutexLock
= MutexLockImpl<SpinMutex, actually_lock>;
typedef DynamicConditionalMutexLockImpl<SpinMutex> DynamicConditionalSpinMutexLock;
/** @} */
} // namespace quickstep
#endif // QUICKSTEP_THREADING_SPIN_MUTEX_HPP_