Threading classes wrappers
parent
f48ebe8557
commit
4e3d4d4ed8
2
SCsub
2
SCsub
|
@ -38,6 +38,8 @@ voxel_files = [
|
|||
"util/noise/fast_noise_lite/*.cpp",
|
||||
"util/noise/gd_noise_range.cpp",
|
||||
|
||||
"util/thread/*.cpp",
|
||||
|
||||
"util/tasks/*.cpp",
|
||||
"util/tasks/godot/*.cpp",
|
||||
|
||||
|
|
|
@ -1,9 +1,11 @@
|
|||
#ifndef VOXEL_GENERATOR_GRAPH_H
|
||||
#define VOXEL_GENERATOR_GRAPH_H
|
||||
|
||||
#include "../../util/thread/rw_lock.h"
|
||||
#include "../voxel_generator.h"
|
||||
#include "program_graph.h"
|
||||
#include "voxel_graph_runtime.h"
|
||||
|
||||
#include <memory>
|
||||
|
||||
class Image;
|
||||
|
|
|
@ -1,8 +1,10 @@
|
|||
#ifndef VOXEL_MESHER_BLOCKY_H
|
||||
#define VOXEL_MESHER_BLOCKY_H
|
||||
|
||||
#include "../../util/thread/rw_lock.h"
|
||||
#include "../voxel_mesher.h"
|
||||
#include "voxel_blocky_library.h"
|
||||
|
||||
#include <core/object/ref_counted.h>
|
||||
#include <scene/resources/mesh.h>
|
||||
#include <vector>
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
#include "../../util/math/vector2f.h"
|
||||
#include "../../util/math/vector3f.h"
|
||||
#include "../../util/thread/rw_lock.h"
|
||||
#include "../voxel_mesher.h"
|
||||
#include "voxel_color_palette.h"
|
||||
|
||||
|
|
|
@ -12,8 +12,6 @@
|
|||
#include "save_block_data_task.h"
|
||||
|
||||
#include <core/config/project_settings.h>
|
||||
#include <core/os/memory.h>
|
||||
#include <thread>
|
||||
|
||||
namespace zylann::voxel {
|
||||
|
||||
|
@ -38,7 +36,7 @@ void VoxelServer::destroy_singleton() {
|
|||
VoxelServer::VoxelServer() {
|
||||
CRASH_COND(ProjectSettings::get_singleton() == nullptr);
|
||||
|
||||
const int hw_threads_hint = std::thread::hardware_concurrency();
|
||||
const int hw_threads_hint = Thread::get_hardware_concurrency();
|
||||
ZN_PRINT_VERBOSE(format("Voxel: HW threads hint: {}", hw_threads_hint));
|
||||
|
||||
// Compute thread count for general pool.
|
||||
|
|
|
@ -288,6 +288,7 @@ struct VoxelFileLockerWrite {
|
|||
String _path;
|
||||
};
|
||||
|
||||
// Helper class to store tasks and schedule them in a single batch
|
||||
class BufferedTaskScheduler {
|
||||
public:
|
||||
static BufferedTaskScheduler &get_for_current_thread();
|
||||
|
|
|
@ -5,10 +5,10 @@
|
|||
#include "../util/fixed_array.h"
|
||||
#include "../util/flat_map.h"
|
||||
#include "../util/math/box3i.h"
|
||||
#include "../util/thread/rw_lock.h"
|
||||
#include "funcs.h"
|
||||
#include "voxel_metadata.h"
|
||||
|
||||
#include <core/os/rw_lock.h>
|
||||
#include <limits>
|
||||
|
||||
namespace zylann::voxel {
|
||||
|
|
|
@ -1,10 +1,7 @@
|
|||
#include "voxel_memory_pool.h"
|
||||
#include "../util/macros.h"
|
||||
#include "../util/profiling.h"
|
||||
|
||||
#include <core/os/os.h>
|
||||
#include <core/string/print_string.h>
|
||||
#include <core/variant/variant.h>
|
||||
#include "../util/string_funcs.h"
|
||||
|
||||
namespace zylann::voxel {
|
||||
|
||||
|
@ -33,7 +30,7 @@ VoxelMemoryPool::VoxelMemoryPool() {}
|
|||
|
||||
VoxelMemoryPool::~VoxelMemoryPool() {
|
||||
#ifdef TOOLS_ENABLED
|
||||
if (OS::get_singleton()->is_stdout_verbose()) {
|
||||
if (is_verbose_output_enabled()) {
|
||||
debug_print();
|
||||
}
|
||||
#endif
|
||||
|
@ -142,28 +139,23 @@ void VoxelMemoryPool::clear() {
|
|||
}
|
||||
|
||||
void VoxelMemoryPool::debug_print() {
|
||||
print_line("-------- VoxelMemoryPool ----------");
|
||||
println("-------- VoxelMemoryPool ----------");
|
||||
for (unsigned int pot = 0; pot < _pot_pools.size(); ++pot) {
|
||||
Pool &pool = _pot_pools[pot];
|
||||
MutexLock lock(pool.mutex);
|
||||
print_line(String("Pool {0}: {1} blocks (capacity {2})")
|
||||
.format(varray(pot, ZN_SIZE_T_TO_VARIANT(pool.blocks.size()),
|
||||
ZN_SIZE_T_TO_VARIANT(pool.blocks.capacity()))));
|
||||
println(format("Pool {}: {} blocks (capacity {})", pot, pool.blocks.size(), pool.blocks.capacity()));
|
||||
}
|
||||
}
|
||||
|
||||
unsigned int VoxelMemoryPool::debug_get_used_blocks() const {
|
||||
//MutexLock lock(_mutex);
|
||||
return _used_blocks;
|
||||
}
|
||||
|
||||
size_t VoxelMemoryPool::debug_get_used_memory() const {
|
||||
//MutexLock lock(_mutex);
|
||||
return _used_memory;
|
||||
}
|
||||
|
||||
size_t VoxelMemoryPool::debug_get_total_memory() const {
|
||||
//MutexLock lock(_mutex);
|
||||
return _total_memory;
|
||||
}
|
||||
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
|
||||
#include "../util/fixed_array.h"
|
||||
#include "../util/math/funcs.h"
|
||||
#include "core/os/mutex.h"
|
||||
#include "../util/thread/mutex.h"
|
||||
|
||||
#include <atomic>
|
||||
#include <limits>
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
#define VOXEL_STREAM_REGION_H
|
||||
|
||||
#include "../../util/fixed_array.h"
|
||||
#include "../../util/thread/mutex.h"
|
||||
#include "../file_utils.h"
|
||||
#include "../voxel_stream.h"
|
||||
#include "region_file.h"
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
#ifndef VOXEL_STREAM_SQLITE_H
|
||||
#define VOXEL_STREAM_SQLITE_H
|
||||
|
||||
#include "../../util/thread/mutex.h"
|
||||
#include "../voxel_block_serializer.h"
|
||||
#include "../voxel_stream.h"
|
||||
#include "../voxel_stream_cache.h"
|
||||
#include <core/os/mutex.h>
|
||||
#include <vector>
|
||||
|
||||
namespace zylann::voxel {
|
||||
|
|
|
@ -2,7 +2,9 @@
|
|||
#define VOXEL_STREAM_H
|
||||
|
||||
#include "../util/memory.h"
|
||||
#include "../util/thread/rw_lock.h"
|
||||
#include "instance_data.h"
|
||||
|
||||
#include <core/io/resource.h>
|
||||
|
||||
namespace zylann::voxel {
|
||||
|
|
|
@ -12,6 +12,8 @@
|
|||
#include "../../util/profiling_clock.h"
|
||||
#include "../../util/string_funcs.h"
|
||||
#include "../../util/tasks/async_dependency_tracker.h"
|
||||
#include "../../util/thread/mutex.h"
|
||||
#include "../../util/thread/rw_lock.h"
|
||||
#include "../instancing/voxel_instancer.h"
|
||||
#include "voxel_lod_terrain_update_task.h"
|
||||
|
||||
|
|
|
@ -2,10 +2,9 @@
|
|||
#define ZN_FILE_LOCKER_H
|
||||
|
||||
#include "errors.h"
|
||||
#include "thread/mutex.h"
|
||||
#include "thread/rw_lock.h"
|
||||
|
||||
#include <core/io/file_access.h>
|
||||
#include <core/os/mutex.h>
|
||||
#include <core/os/rw_lock.h>
|
||||
#include <core/templates/hash_map.h>
|
||||
|
||||
namespace zylann {
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#include "threaded_task_runner.h"
|
||||
#include "../profiling.h"
|
||||
#include "../string_funcs.h"
|
||||
|
||||
#include <core/os/os.h>
|
||||
#include <core/os/time.h>
|
||||
|
||||
namespace zylann {
|
||||
|
@ -32,8 +32,8 @@ void ThreadedTaskRunner::create_thread(ThreadData &d, uint32_t i) {
|
|||
d.stop = false;
|
||||
d.waiting = false;
|
||||
d.index = i;
|
||||
if (!_name.is_empty()) {
|
||||
d.name = String("{0} {1}").format(varray(_name, i));
|
||||
if (!_name.empty()) {
|
||||
d.name = format("{} {}", _name, i);
|
||||
}
|
||||
d.thread.start(thread_func_static, &d);
|
||||
}
|
||||
|
@ -57,7 +57,7 @@ void ThreadedTaskRunner::destroy_all_threads() {
|
|||
}
|
||||
}
|
||||
|
||||
void ThreadedTaskRunner::set_name(String name) {
|
||||
void ThreadedTaskRunner::set_name(const char *name) {
|
||||
_name = name;
|
||||
}
|
||||
|
||||
|
@ -121,12 +121,11 @@ void ThreadedTaskRunner::thread_func_static(void *p_data) {
|
|||
ThreadData &data = *static_cast<ThreadData *>(p_data);
|
||||
ThreadedTaskRunner &pool = *data.pool;
|
||||
|
||||
if (!data.name.is_empty()) {
|
||||
Thread::set_name(data.name);
|
||||
if (!data.name.empty()) {
|
||||
Thread::set_name(data.name.c_str());
|
||||
|
||||
#ifdef ZN_PROFILER_ENABLED
|
||||
CharString thread_name = data.name.utf8();
|
||||
ZN_PROFILE_SET_THREAD_NAME(thread_name.get_data());
|
||||
ZN_PROFILE_SET_THREAD_NAME(data.name.c_str());
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -251,7 +250,7 @@ void ThreadedTaskRunner::wait_for_all_tasks() {
|
|||
}
|
||||
}
|
||||
|
||||
OS::get_singleton()->delay_usec(2000);
|
||||
Thread::sleep_usec(2000);
|
||||
|
||||
if (!error1_reported && Time::get_singleton()->get_ticks_msec() - before > suspicious_delay_msec) {
|
||||
ZN_PRINT_WARNING("Waiting for all tasks to be picked is taking a long time");
|
||||
|
@ -274,7 +273,7 @@ void ThreadedTaskRunner::wait_for_all_tasks() {
|
|||
}
|
||||
}
|
||||
|
||||
OS::get_singleton()->delay_usec(2000);
|
||||
Thread::sleep_usec(2000);
|
||||
|
||||
if (!error2_reported && Time::get_singleton()->get_ticks_msec() - before > suspicious_delay_msec) {
|
||||
ZN_PRINT_WARNING("Waiting for all tasks to be completed is taking a long time");
|
||||
|
|
|
@ -3,16 +3,13 @@
|
|||
|
||||
#include "../fixed_array.h"
|
||||
#include "../span.h"
|
||||
#include "../thread/mutex.h"
|
||||
#include "../thread/semaphore.h"
|
||||
#include "../thread/thread.h"
|
||||
#include "threaded_task.h"
|
||||
|
||||
#include <core/os/mutex.h>
|
||||
#include <core/os/semaphore.h>
|
||||
#include <core/os/thread.h>
|
||||
#include <core/string/ustring.h>
|
||||
|
||||
#include <queue>
|
||||
|
||||
class Thread;
|
||||
#include <string>
|
||||
|
||||
namespace zylann {
|
||||
|
||||
|
@ -33,7 +30,7 @@ public:
|
|||
|
||||
// Set name prefix to recognize threads of this pool in debug tools.
|
||||
// Must be called before configuring thread count.
|
||||
void set_name(String name);
|
||||
void set_name(const char *name);
|
||||
|
||||
// TODO Add ability to change it while running without skipping tasks
|
||||
// Can't be changed after tasks have been queued
|
||||
|
@ -92,7 +89,7 @@ private:
|
|||
bool stop = false;
|
||||
bool waiting = false;
|
||||
State debug_state = STATE_STOPPED;
|
||||
String name;
|
||||
std::string name;
|
||||
|
||||
void wait_to_finish_and_reset() {
|
||||
thread.wait_to_finish();
|
||||
|
@ -125,7 +122,7 @@ private:
|
|||
uint32_t _batch_count = 1;
|
||||
uint32_t _priority_update_period = 32;
|
||||
|
||||
String _name;
|
||||
std::string _name;
|
||||
|
||||
unsigned int _debug_received_tasks = 0;
|
||||
unsigned int _debug_completed_tasks = 0;
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
#define ZYLANN_TIME_SPREAD_TASK_RUNNER_H
|
||||
|
||||
#include "../span.h"
|
||||
#include <core/os/mutex.h>
|
||||
#include "../thread/mutex.h"
|
||||
#include <cstdint>
|
||||
#include <queue>
|
||||
|
||||
|
|
|
@ -0,0 +1,51 @@
|
|||
#ifndef ZN_MUTEX_H
|
||||
#define ZN_MUTEX_H
|
||||
|
||||
#include <mutex>
|
||||
|
||||
namespace zylann {
|
||||
|
||||
template <class StdMutexT>
|
||||
class MutexImpl {
|
||||
mutable StdMutexT mutex;
|
||||
|
||||
public:
|
||||
inline void lock() const {
|
||||
mutex.lock();
|
||||
}
|
||||
|
||||
inline void unlock() const {
|
||||
mutex.unlock();
|
||||
}
|
||||
|
||||
inline bool try_lock() const {
|
||||
return mutex.try_lock();
|
||||
}
|
||||
};
|
||||
|
||||
template <class MutexT>
|
||||
class MutexLock {
|
||||
const MutexT &mutex;
|
||||
|
||||
public:
|
||||
inline explicit MutexLock(const MutexT &p_mutex) : mutex(p_mutex) {
|
||||
mutex.lock();
|
||||
}
|
||||
|
||||
inline ~MutexLock() {
|
||||
mutex.unlock();
|
||||
}
|
||||
};
|
||||
|
||||
using Mutex = MutexImpl<std::recursive_mutex>; // Recursive, for general use
|
||||
using BinaryMutex = MutexImpl<std::mutex>; // Non-recursive, handle with care
|
||||
|
||||
// Don't instantiate these templates in every file where they are used, do it just once
|
||||
extern template class MutexImpl<std::recursive_mutex>;
|
||||
extern template class MutexImpl<std::mutex>;
|
||||
extern template class MutexLock<MutexImpl<std::recursive_mutex>>;
|
||||
extern template class MutexLock<MutexImpl<std::mutex>>;
|
||||
|
||||
} // namespace zylann
|
||||
|
||||
#endif // ZN_MUTEX_H
|
|
@ -0,0 +1,72 @@
|
|||
#ifndef ZN_RW_LOCK_H
|
||||
#define ZN_RW_LOCK_H
|
||||
|
||||
#include <shared_mutex>
|
||||
|
||||
namespace zylann {
|
||||
|
||||
class RWLock {
|
||||
public:
|
||||
// Lock the rwlock, block if locked by someone else
|
||||
void read_lock() const {
|
||||
_mutex.lock_shared();
|
||||
}
|
||||
|
||||
// Unlock the rwlock, let other threads continue
|
||||
void read_unlock() const {
|
||||
_mutex.unlock_shared();
|
||||
}
|
||||
|
||||
// Attempt to lock the rwlock, returns `true` on success, `false` means it can't lock.
|
||||
bool read_try_lock() const {
|
||||
return _mutex.try_lock_shared();
|
||||
}
|
||||
|
||||
// Lock the rwlock, block if locked by someone else
|
||||
void write_lock() {
|
||||
_mutex.lock();
|
||||
}
|
||||
|
||||
// Unlock the rwlock, let other thwrites continue
|
||||
void write_unlock() {
|
||||
_mutex.unlock();
|
||||
}
|
||||
|
||||
// Attempt to lock the rwlock, returns `true` on success, `false` means it can't lock.
|
||||
bool write_try_lock() {
|
||||
return _mutex.try_lock();
|
||||
}
|
||||
|
||||
private:
|
||||
mutable std::shared_timed_mutex _mutex;
|
||||
};
|
||||
|
||||
class RWLockRead {
|
||||
public:
|
||||
RWLockRead(const RWLock &p_lock) : _lock(p_lock) {
|
||||
_lock.read_lock();
|
||||
}
|
||||
~RWLockRead() {
|
||||
_lock.read_unlock();
|
||||
}
|
||||
|
||||
private:
|
||||
const RWLock &_lock;
|
||||
};
|
||||
|
||||
class RWLockWrite {
|
||||
public:
|
||||
RWLockWrite(RWLock &p_lock) : _lock(p_lock) {
|
||||
_lock.write_lock();
|
||||
}
|
||||
~RWLockWrite() {
|
||||
_lock.write_unlock();
|
||||
}
|
||||
|
||||
private:
|
||||
RWLock &_lock;
|
||||
};
|
||||
|
||||
} // namespace zylann
|
||||
|
||||
#endif // ZN_RW_LOCK_H
|
|
@ -0,0 +1,42 @@
|
|||
#ifndef ZN_SEMAPHORE_H
|
||||
#define ZN_SEMAPHORE_H
|
||||
|
||||
#include <condition_variable>
|
||||
#include <mutex>
|
||||
|
||||
namespace zylann {
|
||||
|
||||
class Semaphore {
|
||||
public:
|
||||
inline void post() const {
|
||||
std::lock_guard<decltype(_mutex)> lock(_mutex);
|
||||
++_count;
|
||||
_condition.notify_one();
|
||||
}
|
||||
|
||||
inline void wait() const {
|
||||
std::unique_lock<decltype(_mutex)> lock(_mutex);
|
||||
while (_count != 0) { // Handle spurious wake-ups.
|
||||
_condition.wait(lock);
|
||||
}
|
||||
--_count;
|
||||
}
|
||||
|
||||
inline bool try_wait() const {
|
||||
std::lock_guard<decltype(_mutex)> lock(_mutex);
|
||||
if (_count != 0) {
|
||||
--_count;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private:
|
||||
mutable std::mutex _mutex;
|
||||
mutable std::condition_variable _condition;
|
||||
mutable unsigned long _count = 0; // Initialized as locked.
|
||||
};
|
||||
|
||||
} // namespace zylann
|
||||
|
||||
#endif // ZN_SEMAPHORE_H
|
|
@ -0,0 +1,48 @@
|
|||
#include "thread.h"
|
||||
#include "../memory.h"
|
||||
|
||||
#include <core/os/os.h>
|
||||
#include <core/os/thread.h>
|
||||
#include <core/string/ustring.h>
|
||||
|
||||
namespace zylann {
|
||||
|
||||
struct ThreadImpl {
|
||||
::Thread thread;
|
||||
};
|
||||
|
||||
Thread::Thread() {
|
||||
_impl = ZN_NEW(ThreadImpl);
|
||||
}
|
||||
|
||||
Thread::~Thread() {
|
||||
ZN_DELETE(_impl);
|
||||
}
|
||||
|
||||
void Thread::start(Callback p_callback, void *p_userdata, Priority priority) {
|
||||
::Thread::Settings settings;
|
||||
settings.priority = ::Thread::Priority(priority);
|
||||
_impl->thread.start(p_callback, p_userdata, settings);
|
||||
}
|
||||
|
||||
bool Thread::is_started() const {
|
||||
return _impl->thread.is_started();
|
||||
}
|
||||
|
||||
void Thread::wait_to_finish() {
|
||||
_impl->thread.wait_to_finish();
|
||||
}
|
||||
|
||||
void Thread::set_name(const char *name) {
|
||||
::Thread::set_name(String(name));
|
||||
}
|
||||
|
||||
void Thread::sleep_usec(uint32_t microseconds) {
|
||||
OS::get_singleton()->delay_usec(microseconds);
|
||||
}
|
||||
|
||||
unsigned int Thread::get_hardware_concurrency() {
|
||||
return std::thread::hardware_concurrency();
|
||||
}
|
||||
|
||||
} // namespace zylann
|
|
@ -0,0 +1,40 @@
|
|||
#ifndef ZN_THREAD_H
|
||||
#define ZN_THREAD_H
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
namespace zylann {
|
||||
|
||||
struct ThreadImpl;
|
||||
|
||||
class Thread {
|
||||
public:
|
||||
enum Priority { //
|
||||
PRIORITY_LOW,
|
||||
PRIORITY_NORMAL,
|
||||
PRIORITY_HIGH
|
||||
};
|
||||
|
||||
typedef void (*Callback)(void *p_userdata);
|
||||
|
||||
Thread();
|
||||
~Thread();
|
||||
|
||||
void start(Callback p_callback, void *p_userdata, Priority priority = PRIORITY_NORMAL);
|
||||
bool is_started() const;
|
||||
void wait_to_finish();
|
||||
|
||||
// Gets a hint of the number of concurrent threads natively supported
|
||||
static unsigned int get_hardware_concurrency();
|
||||
|
||||
// Targets the current thread
|
||||
static void set_name(const char *name);
|
||||
static void sleep_usec(uint32_t microseconds);
|
||||
|
||||
private:
|
||||
ThreadImpl *_impl = nullptr;
|
||||
};
|
||||
|
||||
} // namespace zylann
|
||||
|
||||
#endif // ZN_THREAD_H
|
Loading…
Reference in New Issue