- more threading things
TODO: documentation
This commit is contained in:
@@ -302,6 +302,8 @@ add_subdirectory(test)
|
|||||||
|
|
||||||
add_library(fennec STATIC
|
add_library(fennec STATIC
|
||||||
${FENNEC_SOURCES}
|
${FENNEC_SOURCES}
|
||||||
|
include/fennec/threading/mutex.h
|
||||||
|
include/fennec/threading/lock_guard.h
|
||||||
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -25,6 +25,7 @@
|
|||||||
namespace fennec::detail
|
namespace fennec::detail
|
||||||
{
|
{
|
||||||
template<typename TypeT> struct _add_pointer : type_identity<TypeT*> {};
|
template<typename TypeT> struct _add_pointer : type_identity<TypeT*> {};
|
||||||
|
template<typename TypeT> struct _add_pointer<TypeT&> : type_identity<TypeT*> {};
|
||||||
template<typename TypeT> struct _remove_pointer : type_identity<TypeT> {};
|
template<typename TypeT> struct _remove_pointer : type_identity<TypeT> {};
|
||||||
template<typename TypeT> struct _remove_pointer<TypeT*> : type_identity<TypeT> {};
|
template<typename TypeT> struct _remove_pointer<TypeT*> : type_identity<TypeT> {};
|
||||||
|
|
||||||
@@ -43,36 +44,48 @@ namespace fennec::detail
|
|||||||
template<typename TypeT> struct _remove_cv<const volatile TypeT> : type_identity<TypeT> {};
|
template<typename TypeT> struct _remove_cv<const volatile TypeT> : type_identity<TypeT> {};
|
||||||
|
|
||||||
template<typename TypeT>
|
template<typename TypeT>
|
||||||
struct _decay : conditional<_is_const<const TypeT>{}, _remove_cv<TypeT>, _add_pointer<TypeT>> {};
|
struct _decay_selector : conditional_t<_is_const<const TypeT>{}, _remove_cv<TypeT>, _add_pointer<TypeT>> {};
|
||||||
|
|
||||||
template<typename TypeT> requires requires { typename TypeT::element_t; }
|
template<typename TypeT> requires requires { typename TypeT::decay_t; }
|
||||||
struct _decay<TypeT> : type_identity<typename TypeT::decay_t> {};
|
struct _decay_selector<TypeT> : type_identity<typename TypeT::decay_t> {};
|
||||||
|
|
||||||
template<typename TypeT, size_t N>
|
template<typename TypeT, size_t N>
|
||||||
struct _decay<TypeT[N]> : type_identity<TypeT*> {};
|
struct _decay_selector<TypeT[N]> : type_identity<TypeT*> {};
|
||||||
|
|
||||||
template<typename TypeT>
|
template<typename TypeT>
|
||||||
struct _decay<TypeT[]> : type_identity<TypeT*> {};
|
struct _decay_selector<TypeT[]> : type_identity<TypeT*> {};
|
||||||
|
|
||||||
template<typename _Tp, typename = void>
|
template<typename TypeT> struct _decay {
|
||||||
|
using type = typename _decay_selector<TypeT>::type;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename TypeT> struct _decay<TypeT&> {
|
||||||
|
using type = typename _decay_selector<TypeT>::type;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename TypeT> struct _decay<TypeT&&> {
|
||||||
|
using type = typename _decay_selector<TypeT>::type;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename TypeT, typename = void>
|
||||||
struct _add_lvalue_reference {
|
struct _add_lvalue_reference {
|
||||||
using type = _Tp;
|
using type = TypeT;
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename _Tp>
|
template<typename TypeT>
|
||||||
struct _add_lvalue_reference<_Tp, void_t<_Tp&>> {
|
struct _add_lvalue_reference<TypeT, void_t<TypeT&>> {
|
||||||
using type = _Tp&;
|
using type = TypeT&;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
template<typename _Tp, typename = void>
|
template<typename TypeT, typename = void>
|
||||||
struct _add_rvalue_reference {
|
struct _add_rvalue_reference {
|
||||||
using type = _Tp;
|
using type = TypeT;
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename _Tp>
|
template<typename TypeT>
|
||||||
struct _add_rvalue_reference<_Tp, void_t<_Tp&&>> {
|
struct _add_rvalue_reference<TypeT, void_t<TypeT&&>> {
|
||||||
using type = _Tp&&;
|
using type = TypeT&&;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -53,7 +53,9 @@ class function<ReturnT(ArgsT...)> {
|
|||||||
public:
|
public:
|
||||||
///
|
///
|
||||||
/// \brief default constructor
|
/// \brief default constructor
|
||||||
constexpr function() noexcept = default;
|
constexpr function() noexcept
|
||||||
|
: call(nullptr) {
|
||||||
|
}
|
||||||
|
|
||||||
///
|
///
|
||||||
/// \brief destructor
|
/// \brief destructor
|
||||||
@@ -62,7 +64,7 @@ public:
|
|||||||
///
|
///
|
||||||
/// \brief copy constructor
|
/// \brief copy constructor
|
||||||
/// \param func the function to copy
|
/// \param func the function to copy
|
||||||
constexpr function(const function& func) noexcept = default;
|
constexpr function(const function& func) noexcept = default;
|
||||||
|
|
||||||
///
|
///
|
||||||
/// \brief move constructor
|
/// \brief move constructor
|
||||||
|
|||||||
@@ -84,6 +84,15 @@ template<typename T> constexpr T&& forward(remove_reference_t<T>&& x) noexcept {
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
/// \brief Copies \f$v\f$ to a new object of `decay_t<T>`
|
||||||
|
/// \tparam T The type
|
||||||
|
/// \param v The object
|
||||||
|
/// \returns A stack allocated copy of \f$v\f$ in `decay_t<T>`
|
||||||
|
template<typename T> constexpr decay_t<T> decay_copy(T&& v) {
|
||||||
|
return fennec::forward<T>(v);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
///
|
///
|
||||||
/// \brief produces an x-value type to indicate \p x may be "moved"
|
/// \brief produces an x-value type to indicate \p x may be "moved"
|
||||||
///
|
///
|
||||||
|
|||||||
@@ -47,18 +47,6 @@ namespace fennec
|
|||||||
|
|
||||||
class gfxcontext {
|
class gfxcontext {
|
||||||
public:
|
public:
|
||||||
enum texture_ : uint8_t {
|
|
||||||
texture_1d = 0,
|
|
||||||
texture_1d_array,
|
|
||||||
texture_2d,
|
|
||||||
texture_2d_array,
|
|
||||||
texture_multisample,
|
|
||||||
texture_multisample_array,
|
|
||||||
texture_cubemap,
|
|
||||||
texture_cubemap_array,
|
|
||||||
texture_3d,
|
|
||||||
};
|
|
||||||
|
|
||||||
using handle_t = uint32_t;
|
using handle_t = uint32_t;
|
||||||
|
|
||||||
gfxresourcepool resources;
|
gfxresourcepool resources;
|
||||||
|
|||||||
@@ -235,7 +235,7 @@ public:
|
|||||||
/// \param layout The layout of the components in the pixel
|
/// \param layout The layout of the components in the pixel
|
||||||
/// \param bytes The size of the image data in bytes, for compressed pixel formats
|
/// \param bytes The size of the image data in bytes, for compressed pixel formats
|
||||||
texture(GLsizei size, GLsizei mips,
|
texture(GLsizei size, GLsizei mips,
|
||||||
const void* faces[6], GLenum component = BYTE, GLenum layout = R, GLsizei = 0) requires is_2d and cubemap
|
const void* faces[6], GLenum component = BYTE, GLenum layout = R, GLsizei bytes = 0) requires is_2d and cubemap
|
||||||
: _handle(NULL)
|
: _handle(NULL)
|
||||||
, _width(size), _height(size), _depth(1)
|
, _width(size), _height(size), _depth(1)
|
||||||
, _samples(1), _mips(mips) {
|
, _samples(1), _mips(mips) {
|
||||||
@@ -247,6 +247,9 @@ public:
|
|||||||
glTexSubImage2D(base_cubemap_face + i, 0, 0, 0, _width, _height, layout, component, faces[i]);
|
glTexSubImage2D(base_cubemap_face + i, 0, 0, 0, _width, _height, layout, component, faces[i]);
|
||||||
}
|
}
|
||||||
} else if constexpr(compressed) {
|
} else if constexpr(compressed) {
|
||||||
|
for (int i = 0; i < cubemap_faces; ++i) {
|
||||||
|
glCompressedTexImage2D(base_cubemap_face + i, 0, format, _width, _height, 0, bytes, faces[i]);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
for (int i = 0; i < cubemap_faces; ++i) {
|
for (int i = 0; i < cubemap_faces; ++i) {
|
||||||
glTexImage2D(base_cubemap_face + i, 0, format, _width, _height, 0, layout, component, faces[i]);
|
glTexImage2D(base_cubemap_face + i, 0, format, _width, _height, 0, layout, component, faces[i]);
|
||||||
@@ -266,7 +269,7 @@ public:
|
|||||||
///
|
///
|
||||||
/// \details Requires OES_texture_cube_map_array
|
/// \details Requires OES_texture_cube_map_array
|
||||||
texture(GLsizei size, GLsizei depth, GLsizei mips,
|
texture(GLsizei size, GLsizei depth, GLsizei mips,
|
||||||
const void* data, GLenum component = BYTE, GLenum layout = R, GLsizei = 0) requires is_2d and cubemap
|
const void* data, GLenum component = BYTE, GLenum layout = R, GLsizei bytes = 0) requires is_2d and cubemap
|
||||||
: _handle(NULL)
|
: _handle(NULL)
|
||||||
, _width(size), _height(size), _depth(depth)
|
, _width(size), _height(size), _depth(depth)
|
||||||
, _samples(1), _mips(mips) {
|
, _samples(1), _mips(mips) {
|
||||||
@@ -276,6 +279,9 @@ public:
|
|||||||
glTexStorage3D(type, _mips, format, _width, _height, _depth * 6);
|
glTexStorage3D(type, _mips, format, _width, _height, _depth * 6);
|
||||||
glTexSubImage3D(type, 0, 0, 0, 0, _width, _height, _depth * 6, layout, component, data);
|
glTexSubImage3D(type, 0, 0, 0, 0, _width, _height, _depth * 6, layout, component, data);
|
||||||
} else if constexpr(compressed) {
|
} else if constexpr(compressed) {
|
||||||
|
for (int i = 0; i < cubemap_faces; ++i) {
|
||||||
|
glCompressedTexImage3D(type, 0, format, _width, _height, _depth * 6, 0, bytes, data);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
glTexImage3D(type, 0, format, _width, _height, _depth * 6, 0, layout, component, data);
|
glTexImage3D(type, 0, format, _width, _height, _depth * 6, 0, layout, component, data);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -102,6 +102,11 @@ private:
|
|||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
template<typename T>
|
||||||
|
static type_data* get_data() {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
static type_data* get_data() requires(not is_void_v<T>) {
|
static type_data* get_data() requires(not is_void_v<T>) {
|
||||||
auto& typelist = _typelist();
|
auto& typelist = _typelist();
|
||||||
@@ -118,11 +123,6 @@ public:
|
|||||||
return typelist[uuid].get();
|
return typelist[uuid].get();
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
static type_data* get_data() {
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename...Ts>
|
template<typename...Ts>
|
||||||
static dynarray<type_data*> get_data(typelist<Ts...>) {
|
static dynarray<type_data*> get_data(typelist<Ts...>) {
|
||||||
return {
|
return {
|
||||||
|
|||||||
@@ -42,15 +42,15 @@ namespace fennec::detail
|
|||||||
template<typename FuncT, typename...ArgsT> using thread_proxy_t = tuple<FuncT, ArgsT...>;
|
template<typename FuncT, typename...ArgsT> using thread_proxy_t = tuple<FuncT, ArgsT...>;
|
||||||
|
|
||||||
template<typename FuncT, typename...ArgsT, size_t...I>
|
template<typename FuncT, typename...ArgsT, size_t...I>
|
||||||
void _execute_thread(thread_proxy_t<function<FuncT>, ArgsT...>& data, index_metasequence<I...>) {
|
void _execute_thread(thread_proxy_t<FuncT, ArgsT...>& data, index_metasequence<I...>) {
|
||||||
auto func = data.template get<0>();
|
auto func = fennec::move(fennec::get<0>(data));
|
||||||
func(fennec::move(data.template get<I + 1>()) ...);
|
func(fennec::move(fennec::get<I + 1>(data)) ...);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename DataT>
|
template<typename DataT>
|
||||||
void* _run_thread(void* data) {
|
void* _run_thread(void* data) {
|
||||||
unique_ptr<DataT> ptr(data);
|
unique_ptr<DataT> ptr(static_cast<DataT*>(data));
|
||||||
detail::_execute_thread(*ptr, make_index_metasequence_t<DataT::size - 1>{});
|
detail::_execute_thread(*ptr.get(), make_index_metasequence_t<DataT::size - 1>{});
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
58
include/fennec/threading/lock_guard.h
Normal file
58
include/fennec/threading/lock_guard.h
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
// =====================================================================================================================
|
||||||
|
// fennec, a free and open source game engine
|
||||||
|
// Copyright © 2025 Medusa Slockbower
|
||||||
|
//
|
||||||
|
// This program is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
// =====================================================================================================================
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \file lock_guard.h
|
||||||
|
/// \brief
|
||||||
|
///
|
||||||
|
///
|
||||||
|
/// \details
|
||||||
|
/// \author Medusa Slockbower
|
||||||
|
///
|
||||||
|
/// \copyright Copyright © 2025 Medusa Slockbower ([GPLv3](https://www.gnu.org/licenses/gpl-3.0.en.html))
|
||||||
|
///
|
||||||
|
///
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef FENNEC_THREADING_LOCK_GUARD_H
|
||||||
|
#define FENNEC_THREADING_LOCK_GUARD_H
|
||||||
|
|
||||||
|
namespace fennec
|
||||||
|
{
|
||||||
|
|
||||||
|
template<typename MutexT>
|
||||||
|
class lock_guard {
|
||||||
|
public:
|
||||||
|
lock_guard() = delete;
|
||||||
|
|
||||||
|
explicit lock_guard(MutexT& mutex)
|
||||||
|
: mutex(mutex) {
|
||||||
|
mutex.lock();
|
||||||
|
}
|
||||||
|
|
||||||
|
~lock_guard() {
|
||||||
|
mutex.unlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
MutexT& mutex;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // FENNEC_THREADING_LOCK_GUARD_H
|
||||||
79
include/fennec/threading/mutex.h
Normal file
79
include/fennec/threading/mutex.h
Normal file
@@ -0,0 +1,79 @@
|
|||||||
|
// =====================================================================================================================
|
||||||
|
// fennec, a free and open source game engine
|
||||||
|
// Copyright © 2025 Medusa Slockbower
|
||||||
|
//
|
||||||
|
// This program is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
// =====================================================================================================================
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \file mutex.h
|
||||||
|
/// \brief
|
||||||
|
///
|
||||||
|
///
|
||||||
|
/// \details
|
||||||
|
/// \author Medusa Slockbower
|
||||||
|
///
|
||||||
|
/// \copyright Copyright © 2025 Medusa Slockbower ([GPLv3](https://www.gnu.org/licenses/gpl-3.0.en.html))
|
||||||
|
///
|
||||||
|
///
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef FENNEC_THREADING_MUTEX_H
|
||||||
|
#define FENNEC_THREADING_MUTEX_H
|
||||||
|
|
||||||
|
#include <pthread.h>
|
||||||
|
#include <errno.h>
|
||||||
|
|
||||||
|
#include <fennec/lang/assert.h>
|
||||||
|
|
||||||
|
namespace fennec
|
||||||
|
{
|
||||||
|
|
||||||
|
class mutex {
|
||||||
|
public:
|
||||||
|
using handle_t = pthread_mutex_t;
|
||||||
|
|
||||||
|
mutex()
|
||||||
|
: _handle() {
|
||||||
|
assertf((pthread_mutex_init(&_handle, nullptr) == 0), "Failed to initialize mutex.")
|
||||||
|
}
|
||||||
|
~mutex() {
|
||||||
|
assertf((pthread_mutex_destroy(&_handle) == 0), "Failed to destroy mutex.");
|
||||||
|
}
|
||||||
|
|
||||||
|
mutex(const mutex&) = delete;
|
||||||
|
mutex& operator=(const mutex&) = delete;
|
||||||
|
|
||||||
|
void lock() {
|
||||||
|
assertf(pthread_mutex_lock(&_handle) == 0, "Error on lock()!");
|
||||||
|
}
|
||||||
|
|
||||||
|
bool try_lock() {
|
||||||
|
int res = pthread_mutex_trylock(&_handle);
|
||||||
|
assertf(res == EBUSY or res == 0, "Error on trylock()!");
|
||||||
|
return res == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void unlock() {
|
||||||
|
assertf(pthread_mutex_unlock(&_handle) == 0, "Error on unlock()!");
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
pthread_mutex_t _handle;
|
||||||
|
pthread_mutexattr_t _attr;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // FENNEC_THREADING_MUTEX_H
|
||||||
@@ -33,12 +33,13 @@
|
|||||||
#define FENNEC_THREADING_THREAD_H
|
#define FENNEC_THREADING_THREAD_H
|
||||||
|
|
||||||
#include <pthread.h>
|
#include <pthread.h>
|
||||||
#include <fennec/format/formatter.h>
|
|
||||||
#include <fennec/lang/type_traits.h>
|
|
||||||
#include <fennec/lang/type_transforms.h>
|
|
||||||
#include <fennec/memory/bytes.h>
|
#include <fennec/memory/bytes.h>
|
||||||
|
|
||||||
#include <fennec/threading/detail/_thread.h>
|
#include <fennec/threading/detail/_thread.h>
|
||||||
|
|
||||||
|
#include <fennec/format/formatter.h>
|
||||||
|
|
||||||
namespace fennec
|
namespace fennec
|
||||||
{
|
{
|
||||||
|
|
||||||
@@ -47,7 +48,7 @@ private:
|
|||||||
static constexpr pthread_t nullthread = 0;
|
static constexpr pthread_t nullthread = 0;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
using native_handle_type = pthread_t;
|
using handle_t = pthread_t;
|
||||||
|
|
||||||
class id {
|
class id {
|
||||||
public:
|
public:
|
||||||
@@ -89,10 +90,13 @@ public:
|
|||||||
requires(not is_same_v<thread, remove_cvref_t<FuncT>>)
|
requires(not is_same_v<thread, remove_cvref_t<FuncT>>)
|
||||||
thread(FuncT&& func, ArgsT&&...args)
|
thread(FuncT&& func, ArgsT&&...args)
|
||||||
: _handle(nullthread) {
|
: _handle(nullthread) {
|
||||||
using proxy_t = detail::thread_proxy_t<function<FuncT>, ArgsT...>;
|
using proxy_t = detail::thread_proxy_t<decay_t<FuncT>, decay_t<ArgsT>...>;
|
||||||
unique_ptr<proxy_t> proxy = fennec::make_unique<proxy_t>(fennec::forward<FuncT>(func), fennec::forward<ArgsT>(args)...);
|
unique_ptr<proxy_t> proxy = fennec::make_unique<proxy_t>(
|
||||||
|
fennec::decay_copy(fennec::forward<FuncT>(func)),
|
||||||
|
fennec::decay_copy(fennec::forward<ArgsT>(args))...
|
||||||
|
);
|
||||||
|
|
||||||
int_t res = ::pthread_create(&_handle, nullptr, &detail::_run_thread<proxy_t>(), proxy.get());
|
int_t res = ::pthread_create(&_handle, nullptr, &detail::_run_thread<proxy_t>, proxy.get());
|
||||||
assertf(res == 0, "Thread creation failed!");
|
assertf(res == 0, "Thread creation failed!");
|
||||||
|
|
||||||
proxy.release();
|
proxy.release();
|
||||||
@@ -108,7 +112,8 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
~thread() {
|
~thread() {
|
||||||
assertf(_handle == 0, "Attempted to destruct a running thread!");
|
assertf(_handle == 0 or joinable(), "Attempted to destruct a running thread!");
|
||||||
|
join();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool joinable() const noexcept {
|
bool joinable() const noexcept {
|
||||||
@@ -131,7 +136,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
int_t res = pthread_detach(_handle);
|
int_t res = pthread_detach(_handle);
|
||||||
assertf(res == 0, "Failed to detatch thread!");
|
assertf(res == 0, "Failed to detach thread!");
|
||||||
_handle = nullthread;
|
_handle = nullthread;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -155,14 +160,14 @@ private:
|
|||||||
template <>
|
template <>
|
||||||
struct hash<thread::id> {
|
struct hash<thread::id> {
|
||||||
size_t operator()(thread::id v) const noexcept {
|
size_t operator()(thread::id v) const noexcept {
|
||||||
return hash<thread::native_handle_type>()(v._id);
|
return hash<thread::handle_t>()(v._id);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
template<>
|
template<>
|
||||||
struct formatter<thread::id> {
|
struct formatter<thread::id> {
|
||||||
string operator()(const format_arg& fmt, thread::id v) const noexcept {
|
string operator()(const format_arg& fmt, thread::id v) const noexcept {
|
||||||
return formatter<thread::native_handle_type>()(fmt, v._id);
|
return formatter<thread::handle_t>()(fmt, v._id);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -33,13 +33,62 @@
|
|||||||
#define FENNEC_TEST_THREADING_H
|
#define FENNEC_TEST_THREADING_H
|
||||||
|
|
||||||
#include <fennec/threading/atomic.h>
|
#include <fennec/threading/atomic.h>
|
||||||
|
#include <fennec/threading/lock_guard.h>
|
||||||
|
#include <fennec/threading/mutex.h>
|
||||||
|
#include <fennec/threading/thread.h>
|
||||||
|
|
||||||
namespace fennec::test
|
namespace fennec::test
|
||||||
{
|
{
|
||||||
|
|
||||||
|
inline void fennec_test_threading_test_atomic(atomic<size_t>* test_atomic, size_t N = 1000) {
|
||||||
|
for (size_t i = 0; i < N; ++i) {
|
||||||
|
++*test_atomic;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template<size_t ThreadsV>
|
||||||
|
inline void fennec_test_threading_run_test_atomic(array<thread, ThreadsV>& threads, size_t N = 1000) {
|
||||||
|
atomic<size_t> test = 0;
|
||||||
|
for (thread& t : threads) {
|
||||||
|
t = thread(fennec_test_threading_test_atomic, &test, N);
|
||||||
|
}
|
||||||
|
for (thread& t : threads) {
|
||||||
|
t.join();
|
||||||
|
}
|
||||||
|
fennec_test_run(test.load(), N * ThreadsV);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
inline void fennec_test_threading_test_mutex(size_t* var, mutex* m, size_t N = 1000) {
|
||||||
|
for (size_t i = 0; i < N; ++i) {
|
||||||
|
lock_guard guard(*m);
|
||||||
|
++*var;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template<size_t ThreadsV>
|
||||||
|
inline void fennec_test_threading_run_test_mutex(array<thread, ThreadsV>& threads, size_t N = 1000) {
|
||||||
|
mutex m;
|
||||||
|
size_t test = 0;
|
||||||
|
for (thread& t : threads) {
|
||||||
|
t = thread(fennec_test_threading_test_mutex, &test, &m, N);
|
||||||
|
}
|
||||||
|
for (thread& t : threads) {
|
||||||
|
t.join();
|
||||||
|
}
|
||||||
|
fennec_test_run(test, N * ThreadsV);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
inline void fennec_test_threading() {
|
inline void fennec_test_threading() {
|
||||||
|
|
||||||
atomic<bool> test;
|
static constexpr size_t N = 1000, threads = 4;
|
||||||
|
|
||||||
|
array<thread, threads> arr;
|
||||||
|
|
||||||
|
fennec_test_threading_run_test_atomic(arr, N);
|
||||||
|
fennec_test_threading_run_test_mutex(arr, N);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user