Remove ConcurrentSystemLocker and use ReadWriteLock instead of better threading synchronization
This commit is contained in:
@@ -1,75 +0,0 @@
|
||||
// Copyright (c) Wojciech Figat. All rights reserved.
|
||||
|
||||
#include "ConcurrentSystemLocker.h"
|
||||
#include "Engine/Platform/Platform.h"
|
||||
#if !BUILD_RELEASE
|
||||
#include "Engine/Core/Log.h"
|
||||
#endif
|
||||
|
||||
ConcurrentSystemLocker::ConcurrentSystemLocker()
|
||||
{
|
||||
_counters[0] = _counters[1] = 0;
|
||||
}
|
||||
|
||||
void ConcurrentSystemLocker::Begin(bool write, bool exclusively)
|
||||
{
|
||||
volatile int64* thisCounter = &_counters[write];
|
||||
volatile int64* otherCounter = &_counters[!write];
|
||||
|
||||
#if !BUILD_RELEASE
|
||||
int32 retries = 0;
|
||||
double startTime = Platform::GetTimeSeconds();
|
||||
#endif
|
||||
RETRY:
|
||||
#if !BUILD_RELEASE
|
||||
retries++;
|
||||
if (retries > 1000)
|
||||
{
|
||||
double endTime = Platform::GetTimeSeconds();
|
||||
if (endTime - startTime > 0.5f)
|
||||
{
|
||||
LOG(Error, "Deadlock detected in ConcurrentSystemLocker! Thread 0x{0:x} waits for {1} ms...", Platform::GetCurrentThreadID(), (int32)((endTime - startTime) * 1000.0));
|
||||
retries = 0;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// Check if we can enter (cannot read while someone else is writing and vice versa)
|
||||
if (Platform::AtomicRead(otherCounter) != 0)
|
||||
{
|
||||
// Someone else is doing opposite operation so wait for it's end
|
||||
// TODO: use ConditionVariable+CriticalSection to prevent active-waiting
|
||||
Platform::Yield();
|
||||
goto RETRY;
|
||||
}
|
||||
|
||||
// Writers might want to check themselves for a single writer at the same time - just like a mutex
|
||||
if (exclusively && Platform::AtomicRead(thisCounter) != 0)
|
||||
{
|
||||
// Someone else is doing opposite operation so wait for it's end
|
||||
Platform::Yield();
|
||||
goto RETRY;
|
||||
}
|
||||
|
||||
// Mark that we entered this section
|
||||
Platform::InterlockedIncrement(thisCounter);
|
||||
|
||||
// Double-check if we're safe to go
|
||||
if (Platform::InterlockedCompareExchange(otherCounter, 0, 0))
|
||||
{
|
||||
// Someone else is doing opposite operation while this thread was doing counter increment so retry
|
||||
Platform::InterlockedDecrement(thisCounter);
|
||||
goto RETRY;
|
||||
}
|
||||
}
|
||||
|
||||
void ConcurrentSystemLocker::End(bool write)
|
||||
{
|
||||
// Mark that we left this section
|
||||
Platform::InterlockedDecrement(&_counters[write]);
|
||||
}
|
||||
|
||||
bool ConcurrentSystemLocker::HasLock(bool write) const
|
||||
{
|
||||
return Platform::AtomicRead(&_counters[write]) != 0;
|
||||
}
|
||||
@@ -1,47 +0,0 @@
|
||||
// Copyright (c) Wojciech Figat. All rights reserved.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Engine/Core/Core.h"
|
||||
#include "Engine/Core/Types/BaseTypes.h"
|
||||
|
||||
/// <summary>
|
||||
/// Utility for guarding system data access from different threads depending on the resources usage (eg. block read on write).
|
||||
/// </summary>
|
||||
struct ConcurrentSystemLocker
|
||||
{
|
||||
private:
|
||||
volatile int64 _counters[2];
|
||||
|
||||
public:
|
||||
NON_COPYABLE(ConcurrentSystemLocker);
|
||||
ConcurrentSystemLocker();
|
||||
|
||||
void Begin(bool write, bool exclusively = false);
|
||||
void End(bool write);
|
||||
bool HasLock(bool write) const;
|
||||
|
||||
public:
|
||||
template<bool Write>
|
||||
struct Scope
|
||||
{
|
||||
NON_COPYABLE(Scope);
|
||||
|
||||
Scope(ConcurrentSystemLocker& locker, bool exclusively = false)
|
||||
: _locker(locker)
|
||||
{
|
||||
_locker.Begin(Write, exclusively);
|
||||
}
|
||||
|
||||
~Scope()
|
||||
{
|
||||
_locker.End(Write);
|
||||
}
|
||||
|
||||
private:
|
||||
ConcurrentSystemLocker& _locker;
|
||||
};
|
||||
|
||||
typedef Scope<false> ReadScope;
|
||||
typedef Scope<true> WriteScope;
|
||||
};
|
||||
@@ -3,6 +3,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "Engine/Platform/CriticalSection.h"
|
||||
#include "Engine/Platform/ReadWriteLock.h"
|
||||
|
||||
/// <summary>
|
||||
/// Checks if current execution in on the main thread.
|
||||
@@ -10,35 +11,70 @@
|
||||
FLAXENGINE_API bool IsInMainThread();
|
||||
|
||||
/// <summary>
|
||||
/// Scope locker for critical section.
|
||||
/// Scope lock for critical section (mutex). Ensures no other thread can enter scope.
|
||||
/// </summary>
|
||||
class ScopeLock
|
||||
{
|
||||
private:
|
||||
|
||||
const CriticalSection* _section;
|
||||
|
||||
ScopeLock() = default;
|
||||
ScopeLock(const ScopeLock&) = delete;
|
||||
ScopeLock& operator=(const ScopeLock&) = delete;
|
||||
ScopeLock() = delete;
|
||||
NON_COPYABLE(ScopeLock);
|
||||
|
||||
public:
|
||||
|
||||
/// <summary>
|
||||
/// Init, enters critical section.
|
||||
/// </summary>
|
||||
/// <param name="section">The synchronization object to lock.</param>
|
||||
ScopeLock(const CriticalSection& section)
|
||||
FORCE_INLINE ScopeLock(const CriticalSection& section)
|
||||
: _section(§ion)
|
||||
{
|
||||
_section->Lock();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Destructor, releases critical section.
|
||||
/// </summary>
|
||||
~ScopeLock()
|
||||
FORCE_INLINE ~ScopeLock()
|
||||
{
|
||||
_section->Unlock();
|
||||
}
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Scope lock for read/write lock that allows for shared reading by multiple threads (no writers allowed).
|
||||
/// </summary>
|
||||
class ScopeReadLock
|
||||
{
|
||||
private:
|
||||
const ReadWriteLock* _lock;
|
||||
ScopeReadLock() = delete;
|
||||
NON_COPYABLE(ScopeReadLock);
|
||||
|
||||
public:
|
||||
FORCE_INLINE ScopeReadLock(const ReadWriteLock& lock)
|
||||
: _lock(&lock)
|
||||
{
|
||||
_lock->ReadLock();
|
||||
}
|
||||
|
||||
FORCE_INLINE ~ScopeReadLock()
|
||||
{
|
||||
_lock->ReadUnlock();
|
||||
}
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Scope lock for read/write lock that allows for exclusive writing by a single thread (no readers allowed).
|
||||
/// </summary>
|
||||
class ScopeWriteLock
|
||||
{
|
||||
private:
|
||||
const ReadWriteLock* _lock;
|
||||
ScopeWriteLock() = delete;
|
||||
NON_COPYABLE(ScopeWriteLock);
|
||||
|
||||
public:
|
||||
FORCE_INLINE ScopeWriteLock(const ReadWriteLock& lock)
|
||||
: _lock(&lock)
|
||||
{
|
||||
_lock->WriteLock();
|
||||
}
|
||||
|
||||
FORCE_INLINE ~ScopeWriteLock()
|
||||
{
|
||||
_lock->WriteUnlock();
|
||||
}
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user