Sane C++ Libraries
C++ Platform Abstraction Libraries
Loading...
Searching...
No Matches
Threading.h
1// Copyright (c) Stefano Cristiano
2// SPDX-License-Identifier: MIT
3#pragma once
4#include "../Foundation/Compiler.h"
5#ifndef SC_EXPORT_LIBRARY_THREADING
6#define SC_EXPORT_LIBRARY_THREADING 0
7#endif
8#define SC_THREADING_EXPORT SC_COMPILER_LIBRARY_EXPORT(SC_EXPORT_LIBRARY_THREADING)
9
10#include "../Foundation/AlignedStorage.h"
11#include "../Foundation/Function.h"
12#include "../Foundation/Result.h"
13#include "Internal/Optional.h" // UniqueOptional
14
15namespace SC
16{
17
20
23
28struct SC_THREADING_EXPORT Mutex
29{
30 Mutex();
31 ~Mutex();
32
33 // Underlying OS primitives can't be copied or moved
34 Mutex(const Mutex&) = delete;
35 Mutex(Mutex&&) = delete;
36 Mutex& operator=(const Mutex&) = delete;
37 Mutex& operator=(Mutex&&) = delete;
38
39 void lock();
40 void unlock();
41
42 private:
43 friend struct ConditionVariable;
44#if SC_PLATFORM_APPLE
45 static constexpr int OpaqueMutexSize = 56 + sizeof(long);
46 static constexpr int OpaqueMutexAlignment = alignof(long);
47#elif SC_PLATFORM_WINDOWS
48 static constexpr int OpaqueMutexSize = 4 * sizeof(void*) + 2 * sizeof(long);
49 static constexpr int OpaqueMutexAlignment = alignof(void*);
50#elif SC_PLATFORM_EMSCRIPTEN
51 static constexpr int OpaqueMutexSize = sizeof(void*) * 6 + sizeof(long);
52 static constexpr int OpaqueMutexAlignment = alignof(long);
53#else
54 static constexpr int OpaqueMutexSize = sizeof(void*) * 6;
55 static constexpr int OpaqueMutexAlignment = alignof(long);
56#endif
57 // Wrap native mutex as opaque array of bytes
59 OpaqueMutex mutex;
60};
61
63struct SC_THREADING_EXPORT ConditionVariable
64{
67
68 // Underlying OS primitives can't be copied or moved
69 ConditionVariable(const ConditionVariable&) = delete;
71 ConditionVariable& operator=(const ConditionVariable&) = delete;
72 ConditionVariable& operator=(ConditionVariable&&) = delete;
73
74 void wait(Mutex& mutex);
75 void signal();
76 void broadcast();
77
78 private:
79#if SC_PLATFORM_APPLE
80 static constexpr int OpaqueCVSize = 40 + sizeof(long);
81 static constexpr int OpaqueCVAlignment = alignof(long);
82#elif SC_PLATFORM_WINDOWS
83 static constexpr int OpaqueCVSize = sizeof(void*);
84 static constexpr int OpaqueCVAlignment = alignof(void*);
85#elif SC_PLATFORM_EMSCRIPTEN
86 static constexpr int OpaqueCVSize = sizeof(void*) * 12;
87 static constexpr int OpaqueCVAlignment = alignof(long);
88#else
89 static constexpr int OpaqueCVSize = sizeof(void*) * 6;
90 static constexpr int OpaqueCVAlignment = alignof(long);
91#endif
92
93 // Wrap native condition variable as opaque array of bytes
96};
97
118struct SC_THREADING_EXPORT Thread
119{
120 Thread() = default;
121 ~Thread();
122
123 // Cannot be copied or moved (as it would require a dynamic allocation for the type erased Function)
124 Thread(Thread&&) = delete;
125 Thread& operator=(Thread&&) = delete;
126 Thread(const Thread&) = delete;
127 Thread& operator=(const Thread&) = delete;
128
132
135
138 Result start(Function<void(Thread&)>&& func);
139
143 void setThreadName(const native_char_t* name);
144
148
153
156 [[nodiscard]] bool wasStarted() const;
157
160 static void Sleep(uint32_t milliseconds);
161
162 private:
163 void setThreadNameInternal(const native_char_t* name);
164 struct Internal;
165 using OpaqueThread = AlignedStorage<sizeof(void*), alignof(void*)>;
166 UniqueOptional<OpaqueThread> thread;
167 Function<void(Thread&)> userFunction;
168};
169
174struct SC_THREADING_EXPORT RWLock
175{
176 RWLock() = default;
177 ~RWLock() = default;
178
179 RWLock(const RWLock&) = delete;
180 RWLock(RWLock&&) = delete;
181 RWLock& operator=(const RWLock&) = delete;
182 RWLock& operator=(RWLock&&) = delete;
183
185 void lockRead();
186
189
191 void lockWrite();
192
195
196 private:
197 Mutex mutex;
198
199 ConditionVariable readersQ;
200 ConditionVariable writersQ;
201
202 int activeReaders = 0;
203 int waitingWriters = 0;
204 bool writerActive = false;
205};
206
211struct SC_THREADING_EXPORT Barrier
212{
215 Barrier(uint32_t count) : threadCount(count) {}
216
218 void wait();
219
220 private:
221 const uint32_t threadCount;
222
223 uint32_t waitCount = 0;
224 uint32_t generation = 0;
225 Mutex mutex;
226
227 ConditionVariable condition;
228};
229
234struct SC_THREADING_EXPORT EventObject
235{
236 bool autoReset = true;
237
239 void wait();
240
242 void signal();
243
244 private:
245 bool isSignaled = false;
246 Mutex mutex;
247
249};
250
255struct SC_THREADING_EXPORT Semaphore
256{
259 Semaphore(int initialCount = 0);
260
262 void acquire();
263
265 void release();
266
267 private:
268 int count;
269 Mutex mutex;
270
271 ConditionVariable condition;
272};
273
275} // namespace SC
struct SC_FOUNDATION_EXPORT Function
Wraps function pointers, member functions and lambdas without ever allocating.
Definition Function.h:19
unsigned long long uint64_t
Platform independent (8) bytes unsigned int.
Definition PrimitiveTypes.h:33
unsigned int uint32_t
Platform independent (4) bytes unsigned int.
Definition PrimitiveTypes.h:29
char native_char_t
The native char for the platform (wchar_t (4 bytes) on Windows, char (1 byte) everywhere else )
Definition PrimitiveTypes.h:25
A synchronization point that blocks threads until the required number of threads have reached it.
Definition Threading.h:212
Barrier(uint32_t count)
Creates a barrier that waits for the specified number of threads.
Definition Threading.h:215
void wait()
Wait at the barrier until all threads have reached it.
A native OS condition variable.
Definition Threading.h:64
An automatically reset event object to synchronize two threads.
Definition Threading.h:235
void signal()
Unblocks another thread, waiting on EventObject::wait.
void wait()
Waits on a thread for EventObject::signal to be called from another thread.
A native OS mutex to synchronize access to shared resources.
Definition Threading.h:29
A Read-Write lock that allows multiple concurrent readers but only one writer.
Definition Threading.h:175
void lockWrite()
Acquire a write lock. Only one writer can hold the lock, and no readers can hold it simultaneously.
void unlockWrite()
Release a previously acquired write lock.
void lockRead()
Acquire a read lock. Multiple readers can hold the lock concurrently.
void unlockRead()
Release a previously acquired read lock.
An ascii string used as boolean result. SC_TRY macro forwards errors to caller.
Definition Result.h:13
A semaphore synchronization primitive that maintains a count for resource management.
Definition Threading.h:256
void acquire()
Wait for a resource to become available.
void release()
Make a resource available.
Semaphore(int initialCount=0)
Creates a semaphore with an initial count.
A native OS thread.
Definition Threading.h:119
bool wasStarted() const
Check if thread has been started.
static void Sleep(uint32_t milliseconds)
Puts current thread to sleep.
Result start(Function< void(Thread &)> &&func)
Starts the new thread with given name and func.
void setThreadName(const native_char_t *name)
Sets current thread name ONLY if called from inside the thread.
Result detach()
Detaches the thread so that its resources are automatically released back to the system without Threa...
static uint64_t CurrentThreadID()
Returns thread id of the thread calling the function.
uint64_t threadID()
Returns thread id of this thread object (not current thread)
Result join()
Waits for thread to finish and releases its resources.