Wildmeshing Toolkit
Loading...
Searching...
No Matches
Public Member Functions | Static Public Member Functions | Private Attributes | List of all members
wmtk::threading::VertexMutex Class Reference

A per-vertex lock plus the id of the thread currently holding it. More...

#include <vertex_mutex.hpp>

Public Member Functions

 VertexMutex (const VertexMutex &) noexcept
 
 VertexMutex (VertexMutex &&) noexcept
 
VertexMutexoperator= (const VertexMutex &) noexcept
 
VertexMutexoperator= (VertexMutex &&) noexcept
 
bool trylock ()
 
void unlock ()
 
int get_owner () const
 
void set_owner (int n)
 
void reset_owner ()
 

Static Public Member Functions

static constexpr int no_owner ()
 Sentinel stored in the owner field when no thread holds the vertex.
 

Private Attributes

spin_mutex m_mutex
 
std::atomic< int > m_owner {no_owner()}
 

Detailed Description

A per-vertex lock plus the id of the thread currently holding it.

One of these exists per vertex in TriMesh and TetMesh. Before running a topology-changing operation a thread claims every vertex in the operation's one- or two-ring; on any failure it releases what it has taken and the operation is retried later. spin_mutex provides the mutual exclusion; the owner field exists only so that the ring walks can tell "already mine" from "someone else's".

That distinction is load-bearing because spin_mutex is not recursive. A two-ring walk visits the same vertex many times (a vertex is in the one-ring of several of its neighbours), so without the owner check the walk would try to re-lock vertices it already holds, fail, and abort an operation that should have succeeded.

Note
This class was previously duplicated as a nested VertexMutex in both TriMesh.h and TetMesh.h. The two copies drifted – TriMesh's unlock() cleared the owner before releasing the mutex and TetMesh's did it after, which is a bug (see below) – so they are unified here.

Constructor & Destructor Documentation

◆ VertexMutex()

wmtk::threading::VertexMutex::VertexMutex ( const VertexMutex )
inlinenoexcept

Copy and move reset to unlocked-and-unowned rather than propagating state, mirroring spin_mutex. These exist only so a std::vector<VertexMutex> can be grown by resize_vertex_mutex(), which happens single-threaded during mesh (re)initialization when nothing is held. std::atomic is neither copyable nor movable, so without these the vector would not compile.

Member Function Documentation

◆ get_owner()

int wmtk::threading::VertexMutex::get_owner ( ) const
inline

Read the owning thread id, or no_owner().

Deliberately callable without holding the lock – that is precisely how the ring walks use it – which is why the field has to be atomic rather than a plain int.

Relaxed ordering is sufficient, and the reasoning is worth keeping because the field looks like it wants an acquire/release pair and does not need one:

  • A thread only ever writes its own id into a vertex it holds, and clears it before releasing. A thread reading its own id back is reading its own most recent write to a single atomic object, which program order guarantees regardless of ordering.
  • A thread reading some other id, or a stale no_owner(), falls through to trylock(), and the spin_mutex's acquire/release pair is the real arbiter. A stale answer there costs one wasted attempt, never correctness.

The mutual exclusion and the memory visibility of everything the operation touches come from spin_mutex, not from this field.


The documentation for this class was generated from the following file: