Wildmeshing Toolkit
Loading...
Searching...
No Matches
vertex_mutex.hpp
1#pragma once
2
3#include <wmtk/threading/spin_mutex.hpp>
4
5#include <atomic>
6#include <limits>
7
8namespace wmtk::threading {
9
29{
30public:
32 static constexpr int no_owner() { return std::numeric_limits<int>::max(); }
33
34 VertexMutex() = default;
35
43 VertexMutex(const VertexMutex&) noexcept {}
44 VertexMutex(VertexMutex&&) noexcept {}
45 VertexMutex& operator=(const VertexMutex&) noexcept { return *this; }
46 VertexMutex& operator=(VertexMutex&&) noexcept { return *this; }
47
48 bool trylock() { return m_mutex.try_lock(); }
49
50 void unlock()
51 {
52 // Clear the owner BEFORE releasing the mutex, never after.
53 //
54 // With the two swapped there is a window in which the vertex is free but still stamped
55 // with the departing thread's id. Another thread can acquire it and stamp its own id
56 // inside that window, and the departing thread's clear then lands on top -- wiping the
57 // *new* owner's stamp. The new owner subsequently reads `no_owner()` for a vertex it
58 // actually holds, tries to lock it again, fails (the spin_mutex is not recursive) and
59 // aborts an operation that had already succeeded in claiming its whole ring.
60 //
61 // The window is only a couple of instructions wide, so it does not reproduce by timing
62 // in an optimized build; under ThreadSanitizer it showed up as 24 violations in 28k
63 // acquisitions. See the `vertex_mutex_owner_integrity` test.
64 reset_owner();
65 m_mutex.unlock();
66 }
67
87 int get_owner() const { return m_owner.load(std::memory_order_relaxed); }
88
89 void set_owner(int n) { m_owner.store(n, std::memory_order_relaxed); }
90
91 void reset_owner() { m_owner.store(no_owner(), std::memory_order_relaxed); }
92
93private:
94 spin_mutex m_mutex;
95 std::atomic<int> m_owner{no_owner()};
96};
97
98} // namespace wmtk::threading
A per-vertex lock plus the id of the thread currently holding it.
Definition vertex_mutex.hpp:29
static constexpr int no_owner()
Sentinel stored in the owner field when no thread holds the vertex.
Definition vertex_mutex.hpp:32
int get_owner() const
Definition vertex_mutex.hpp:87
VertexMutex(const VertexMutex &) noexcept
Definition vertex_mutex.hpp:43