Stroika Library
3.0d16
Help-Home
Loading...
Searching...
No Matches
SpinLock.h
Go to the documentation of this file.
1
/*
2
* Copyright(c) Sophist Solutions, Inc. 1990-2025. All rights reserved
3
*/
4
#ifndef _Stroika_Foundation_Execution_SpinLock_h_
5
#define _Stroika_Foundation_Execution_SpinLock_h_ 1
6
7
#include "Stroika/Foundation/StroikaPreComp.h"
8
9
#include <atomic>
10
11
#include "Stroika/Foundation/Common/Common.h"
12
#include "
Stroika/Foundation/Common/Enumeration.h
"
13
#include "
Stroika/Foundation/Time/Realtime.h
"
14
15
/**
16
* \file
17
*/
18
19
namespace
Stroika::Foundation::Execution
{
20
21
/**
22
* SpinLock and mutex can be nearly used interchangeably. Oftentimes, users will want to define a typedef which selects
23
* the faster implementation.
24
*
25
* \note Stroika 2.0a155 and earlier - Execution::kSpinLock_IsFasterThan_mutex was always true
26
*
27
* \note Stroika 2.0a156 and later - due to threadFence and http://stroika-bugs.sophists.com/browse/STK-494 - SpinLock
28
* slowed slightly, but its still notably faster (with the default barrier style) on gcc/unix/windows (x86 only tested).
29
*/
30
constexpr
bool
kSpinLock_IsFasterThan_mutex
=
true
;
31
32
/**
33
* Implementation based on
34
* http://en.cppreference.com/w/cpp/atomic/atomic_flag
35
*
36
* About to run tests to compare performance numbers. But this maybe useful for at least some(many) cases.
37
*
38
* \note - SpinLock - though generally faster than most mutexes for short accesses, are not recursive mutexes!
39
*
40
* \note ***Not Cancelation Point***
41
* SpinLock contains no cancelation points, and so can be used interchangeably with mutex - just for the performance differences
42
*
43
* \note From http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2013/n3690.pdf
44
* 1.10 Multi-threaded executions and data races [intro.multithread]
45
*
46
* "A synchronization operation without an associated memory location is a fence and
47
* can be either an acquire fence, a release fence, or both an acquire and release fence"
48
*
49
* Since a spinlock once acquired - can be used to assume assocated data (the data protected by the spinlock mutex)
50
* is up to date with respect to other threads and acquire is needed on the lock. And to assure any changes made with
51
* the lock are seen in other threads a release atomic_fence() is required on the unlock.
52
*
53
* This is the DEFAULT behavior we provide with the default BarrierType - eReleaseAcquire
54
*
55
* \note More good references (to verify if this logic is right - which I'm not 100% clear on)
56
* o https://www.boost.org/doc/libs/1_54_0/doc/html/atomic/usage_examples.html#boost_atomic.usage_examples.example_spinlock
57
* o https://blog.regehr.org/archives/2173
58
* This strongly suggests I may want to do a more fair spinlock, but doesn't appear to have
59
* the fences. In fact, he alleges if you do procedure properly you dont need the fence.
60
* HMM. Need good test cases before I can really play around with this very safely.
61
*/
62
class
SpinLock
{
63
public
:
64
/**
65
* @see std::atomic_thread_fence ()
66
* @see std::memory_order
67
*
68
* \note subtly - eReleaseAcquire means acquire on lock, and release on unlock. This is the natural default for a mutex.
69
*/
70
enum class
BarrierType
{
71
eNoBarrier,
72
eReleaseAcquire,
73
eMemoryTotalOrder,
74
75
eDEFAULT = eReleaseAcquire,
76
77
Stroika_Define_Enum_Bounds
(eNoBarrier, eMemoryTotalOrder)
78
};
79
80
public
:
81
/**
82
* In typical usage, one would use a SpinLock as a mutex, and expect it to create a memory fence.
83
* However, sometimes you want to spinlock and handle the memory ordering yourself. So that feature
84
* is optional (defaulting to the safer, but slower - true).
85
*/
86
SpinLock
(
BarrierType
barrier = BarrierType::eDEFAULT);
87
SpinLock
(
const
SpinLock
&) =
delete
;
88
89
public
:
90
~SpinLock
() =
default
;
91
92
public
:
93
nonvirtual
SpinLock
& operator= (
const
SpinLock
&) =
delete
;
94
95
public
:
96
/**
97
*/
98
nonvirtual
bool
try_lock ();
99
100
public
:
101
/**
102
*/
103
nonvirtual
void
lock ();
104
105
public
:
106
/**
107
*/
108
nonvirtual
void
unlock ();
109
110
private
:
111
BarrierType
fBarrierFlag_;
112
113
private
:
114
#if (__cplusplus < kStrokia_Foundation_Common_cplusplus_20)
115
atomic_flag fLock_ = ATOMIC_FLAG_INIT;
116
#else
117
atomic_flag fLock_;
118
#endif
119
};
120
121
}
122
123
/*
124
********************************************************************************
125
***************************** Implementation Details ***************************
126
********************************************************************************
127
*/
128
#include "SpinLock.inl"
129
130
#endif
/*_Stroika_Foundation_Execution_SpinLock_h_*/
Enumeration.h
Stroika_Define_Enum_Bounds
#define Stroika_Define_Enum_Bounds(FIRST_ITEM, LAST_ITEM)
Definition
Enumeration.h:109
Realtime.h
Stroika::Foundation::Execution::SpinLock
Definition
SpinLock.h:62
Stroika::Foundation::Execution::SpinLock::BarrierType
BarrierType
Definition
SpinLock.h:70
Stroika::Foundation::Execution
Definition
SDKString.inl:7
Stroika::Foundation::Execution::kSpinLock_IsFasterThan_mutex
constexpr bool kSpinLock_IsFasterThan_mutex
Definition
SpinLock.h:30
Library
Sources
Stroika
Foundation
Execution
SpinLock.h
Generated by
1.9.8