flatten 20260225
This commit is contained in:
129
tjp/core/threads/SpinMutex.hpp
Executable file
129
tjp/core/threads/SpinMutex.hpp
Executable file
@@ -0,0 +1,129 @@
|
||||
// License: Modified MIT (NON-AI)
|
||||
// See the LICENSE file in the root directory for license information.
|
||||
// Copyright 2025 Timothy Prepscius
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Lock.hpp"
|
||||
#include "LockedBy.hpp"
|
||||
#include "Atomic.hpp"
|
||||
#include "TryLockGuard.hpp"
|
||||
#include "UnlockGuard.hpp"
|
||||
|
||||
#include "../debug/Debug.h"
|
||||
|
||||
namespace tjp::core {
|
||||
|
||||
// https://probablydance.com/2019/12/30/measuring-mutexes-spinlocks-and-how-bad-the-linux-scheduler-really-is/
|
||||
|
||||
struct SpinMutexLog
|
||||
{
|
||||
Atomic<size_t> tries, failures;
|
||||
|
||||
inline
|
||||
void failed ()
|
||||
{
|
||||
tries++;
|
||||
failures++;
|
||||
}
|
||||
|
||||
inline
|
||||
void succeeded ()
|
||||
{
|
||||
tries++;
|
||||
}
|
||||
} ;
|
||||
|
||||
#ifdef _DEBUG
|
||||
void spin_log();
|
||||
#define SPIN_LOG() spin_log()
|
||||
#else
|
||||
#define SPIN_LOG()
|
||||
#endif
|
||||
|
||||
struct SpinMutex_
|
||||
{
|
||||
#ifdef _DEBUG
|
||||
static SpinMutexLog log;
|
||||
#endif
|
||||
|
||||
static constexpr int threshold = 16;
|
||||
|
||||
inline void micropause() const
|
||||
{
|
||||
// _mm_pause();
|
||||
}
|
||||
|
||||
void lock()
|
||||
{
|
||||
for (int spin_count = 0; !try_lock(); ++spin_count)
|
||||
{
|
||||
DEBUG_ONLY(log.failed());
|
||||
|
||||
if (spin_count < threshold)
|
||||
{
|
||||
micropause();
|
||||
}
|
||||
else
|
||||
{
|
||||
std::this_thread::yield();
|
||||
spin_count = 0;
|
||||
}
|
||||
}
|
||||
|
||||
DEBUG_ONLY(log.succeeded());
|
||||
}
|
||||
|
||||
bool try_lock()
|
||||
{
|
||||
return !locked.load(std::memory_order_relaxed) && !locked.exchange(true, std::memory_order_acquire);
|
||||
}
|
||||
|
||||
void unlock()
|
||||
{
|
||||
locked.store(false, std::memory_order_release);
|
||||
}
|
||||
|
||||
private:
|
||||
Atomic<bool> locked { false };
|
||||
};
|
||||
|
||||
#ifdef DEBUG
|
||||
|
||||
struct SpinMutex : LockedBy<SpinMutex_>
|
||||
{
|
||||
typedef std::lock_guard<SpinMutex> Lock;
|
||||
typedef UnlockGuard<SpinMutex> Unlock;
|
||||
typedef TryLockGuard<SpinMutex> TryLock;
|
||||
} ;
|
||||
|
||||
#else
|
||||
|
||||
struct SpinMutex : SpinMutex_
|
||||
{
|
||||
typedef std::lock_guard<SpinMutex> Lock;
|
||||
typedef UnlockGuard<SpinMutex> Unlock;
|
||||
typedef TryLockGuard<SpinMutex> TryLock;
|
||||
} ;
|
||||
|
||||
#endif
|
||||
|
||||
inline
|
||||
auto lock_of(SpinMutex &m)
|
||||
{
|
||||
return SpinMutex::Lock(m);
|
||||
}
|
||||
|
||||
inline
|
||||
auto try_lock_of(SpinMutex &m)
|
||||
{
|
||||
return SpinMutex::TryLock(m);
|
||||
}
|
||||
|
||||
inline
|
||||
auto unlock_of(SpinMutex &m)
|
||||
{
|
||||
return SpinMutex::Unlock(m);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
Reference in New Issue
Block a user