Fix ThreadLocal when thread count limit is low on a target platform or if it's only main-thread

This commit is contained in:
Wojtek Figat
2026-02-16 11:59:12 +01:00
parent 25e90deed6
commit 3d206e06d0
2 changed files with 61 additions and 4 deletions

View File

@@ -75,7 +75,7 @@ public:
namespace
{
JobSystemService JobSystemInstance;
Thread* Threads[PLATFORM_THREADS_LIMIT / 2] = {};
Thread* Threads[(PLATFORM_THREADS_LIMIT + 1) / 2] = {};
int32 ThreadsCount = 0;
bool JobStartingOnDispatch = true;
volatile int64 ExitFlag = 0;

View File

@@ -7,10 +7,12 @@
#define THREAD_LOCAL_USE_DYNAMIC_BUCKETS (PLATFORM_DESKTOP)
#if PLATFORM_THREADS_LIMIT > 1
/// <summary>
/// Per-thread local variable storage for basic types (POD). Implemented using atomic with per-thread storage indexed via thread id hashing. Consider using 'THREADLOCAL' define before the variable instead.
/// </summary>
template<typename T, int32 MaxThreads = PLATFORM_THREADS_LIMIT>
template<typename T, int32 MaxThreads = (PLATFORM_THREADS_LIMIT >= 16 ? PLATFORM_THREADS_LIMIT : 16)>
class ThreadLocal
{
protected:
@@ -63,7 +65,7 @@ public:
#if THREAD_LOCAL_USE_DYNAMIC_BUCKETS
if (auto dynamicBuckets = (Bucket*)Platform::AtomicRead((intptr volatile*)&_dynamicBuckets))
{
for (int32 i = 0; i < MaxThreads; i++)
for (int32 i = 0; i < DynamicMaxThreads; i++)
{
if (Platform::AtomicRead((int64 volatile*)&dynamicBuckets[i].ThreadID) != 0)
result++;
@@ -84,7 +86,7 @@ public:
#if THREAD_LOCAL_USE_DYNAMIC_BUCKETS
if (auto dynamicBuckets = (Bucket*)Platform::AtomicRead((intptr volatile*)&_dynamicBuckets))
{
for (int32 i = 0; i < MaxThreads; i++)
for (int32 i = 0; i < DynamicMaxThreads; i++)
{
if (Platform::AtomicRead((int64 volatile*)&dynamicBuckets[i].ThreadID) != 0)
result.Add(dynamicBuckets[i].Value);
@@ -154,3 +156,58 @@ protected:
return *(Bucket*)nullptr;
}
};
#else
/// <summary>
/// Single-threaded version of thread local variable storage for basic types (POD).
/// </summary>
template<typename T, int32 MaxThreads = 1>
class ThreadLocal
{
protected:
static_assert(TIsPODType<T>::Value, "Only POD types are supported");
T _value;
bool _set = false;
public:
ThreadLocal()
{
Platform::MemoryClear(&_value, sizeof(_value));
_set = false;
}
public:
FORCE_INLINE T& Get()
{
_set = true;
return _value;
}
FORCE_INLINE void Set(const T& value)
{
_value = value;
_set = true;
}
FORCE_INLINE int32 Count() const
{
return _set ? 1 : 0;
}
template<typename AllocationType = HeapAllocation>
FORCE_INLINE void GetValues(Array<T, AllocationType>& result) const
{
if (_set)
result.Add(_value);
}
FORCE_INLINE void Clear()
{
Platform::MemoryClear(&_value, sizeof(_value));
_set = false;
}
};
#endif