66
77namespace tsom
88{
9+ namespace Detail
10+ {
11+ template <bool Write, typename T>
12+ void LockChunk (T* chunk)
13+ {
14+ if constexpr (Write)
15+ chunk->LockWrite ();
16+ else
17+ chunk->LockRead ();
18+ }
19+
20+ template <bool Write, typename T>
21+ bool TryLockChunk (T* chunk)
22+ {
23+ if constexpr (Write)
24+ return chunk->TryLockWrite ();
25+ else
26+ return chunk->TryLockRead ();
27+ }
28+
29+ template <bool Write, typename T>
30+ void UnlockChunk (T* chunk)
31+ {
32+ if constexpr (Write)
33+ chunk->UnlockWrite ();
34+ else
35+ chunk->UnlockRead ();
36+ }
37+ }
38+
939 template <bool Write>
1040 ChunkLock<Write>::ChunkLock(ChunkType chunk) :
1141 m_chunk (chunk),
@@ -46,23 +76,17 @@ namespace tsom
4676 void ChunkLock<Write>::Lock()
4777 {
4878 NazaraAssertMsg (!m_isLocked, " ChunkLock is already locked" );
49- if constexpr (Write)
50- m_chunk->LockWrite ();
51- else
52- m_chunk->LockRead ();
5379
80+ Detail::LockChunk<Write>(m_chunk);
5481 m_isLocked = true ;
5582 }
5683
5784 template <bool Write>
5885 void ChunkLock<Write>::Unlock()
5986 {
6087 NazaraAssertMsg (m_isLocked, " ChunkLock isn't locked" );
61- if constexpr (Write)
62- m_chunk->UnlockWrite ();
63- else
64- m_chunk->UnlockRead ();
6588
89+ Detail::UnlockChunk<Write>(m_chunk);
6690 m_isLocked = false ;
6791 }
6892
@@ -91,6 +115,7 @@ namespace tsom
91115 void MultiChunkLock<Write, Max>::AddChunk(ChunkType chunk)
92116 {
93117 NazaraAssertMsg (!m_isLocked, " ChunkLock is already locked" );
118+ NazaraAssertMsg (std::find (m_chunks.begin (), m_chunks.end (), chunk) == m_chunks.end (), " Chunk is already in the list" );
94119 m_chunks.push_back (chunk);
95120 }
96121
@@ -99,24 +124,32 @@ namespace tsom
99124 {
100125 // Algorithm to lock every chunk without deadlock
101126 std::size_t lastFailureMutex = Nz::MaxValue ();
127+
102128 for (;;)
103129 {
104130 bool succeeded = true ;
105131 for (std::size_t i = 0 ; i < m_chunks.size (); ++i)
106132 {
107- if (i != lastFailureMutex && !m_chunks[i]->TryLockRead ())
108- {
109- succeeded = false ;
110-
111- // Lock failed, unlock everything and try again
112- for (std::size_t j = 0 ; j < i; ++j)
113- m_chunks[j]->UnlockRead ();
114-
115- // Lock blocked chunk first to pause thread
116- m_chunks[i]->LockRead ();
117- lastFailureMutex = i;
118- break ;
119- }
133+ if (i == lastFailureMutex)
134+ continue ;
135+
136+ if (Detail::TryLockChunk<Write>(m_chunks[i]))
137+ continue ;
138+
139+ // Lock failed, unlock everything and try again
140+ succeeded = false ;
141+
142+ for (std::size_t j = 0 ; j < i; ++j)
143+ Detail::UnlockChunk<Write>(m_chunks[j]);
144+
145+ if (lastFailureMutex > i && lastFailureMutex < m_chunks.size ())
146+ Detail::UnlockChunk<Write>(m_chunks[lastFailureMutex]);
147+
148+ // Lock blocked chunk first to pause thread
149+ Detail::LockChunk<Write>(m_chunks[i]);
150+
151+ lastFailureMutex = i;
152+ break ;
120153 }
121154
122155 if (succeeded)
@@ -131,7 +164,7 @@ namespace tsom
131164 {
132165 NazaraAssertMsg (m_isLocked, " ChunkLock isn't locked" );
133166 for (const Chunk* chunk : m_chunks)
134- chunk-> UnlockRead ( );
167+ Detail::UnlockChunk<Write>(chunk );
135168
136169 m_isLocked = false ;
137170 }
0 commit comments