Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'source/blender/functions/FN_lazy_function.hh')
-rw-r--r--source/blender/functions/FN_lazy_function.hh66
1 files changed, 62 insertions, 4 deletions
diff --git a/source/blender/functions/FN_lazy_function.hh b/source/blender/functions/FN_lazy_function.hh
index 59a3a90b0b0..4a539e7cbd1 100644
--- a/source/blender/functions/FN_lazy_function.hh
+++ b/source/blender/functions/FN_lazy_function.hh
@@ -43,6 +43,13 @@
#include "BLI_linear_allocator.hh"
#include "BLI_vector.hh"
+#include <atomic>
+#include <thread>
+
+#ifdef DEBUG
+# define FN_LAZY_FUNCTION_DEBUG_THREADS
+#endif
+
namespace blender::fn::lazy_function {
enum class ValueUsage {
@@ -102,9 +109,13 @@ class Params {
* The lazy-function this #Params has been prepared for.
*/
const LazyFunction &fn_;
+#ifdef FN_LAZY_FUNCTION_DEBUG_THREADS
+ std::thread::id main_thread_id_;
+ std::atomic<bool> allow_multi_threading_;
+#endif
public:
- Params(const LazyFunction &fn);
+ Params(const LazyFunction &fn, bool allow_multi_threading_initially);
/**
* Get a pointer to an input value if the value is available already. Otherwise null is returned.
@@ -154,7 +165,7 @@ class Params {
* Typed utility methods that wrap the methods above.
*/
template<typename T> T extract_input(int index);
- template<typename T> const T &get_input(int index);
+ template<typename T> const T &get_input(int index) const;
template<typename T> T *try_get_input_data_ptr_or_request(int index);
template<typename T> void set_output(int index, T &&value);
@@ -163,7 +174,15 @@ class Params {
*/
void set_default_remaining_outputs();
+ /**
+ * Returns true when the lazy-function is now allowed to use multi-threading when interacting
+ * with this #Params. That means, it is allowed to call non-const methods from different threads.
+ */
+ bool try_enable_multi_threading();
+
private:
+ void assert_valid_thread() const;
+
/**
* Methods that need to be implemented by subclasses. Those are separate from the non-virtual
* methods above to make it easy to insert additional debugging logic on top of the
@@ -176,6 +195,7 @@ class Params {
virtual bool output_was_set_impl(int index) const = 0;
virtual ValueUsage get_output_usage_impl(int index) const = 0;
virtual void set_input_unused_impl(int index) = 0;
+ virtual bool try_enable_multi_threading_impl();
};
/**
@@ -312,7 +332,14 @@ inline void LazyFunction::execute(Params &params, const Context &context) const
/** \name #Params Inline Methods
* \{ */
-inline Params::Params(const LazyFunction &fn) : fn_(fn)
+inline Params::Params(const LazyFunction &fn,
+ [[maybe_unused]] bool allow_multi_threading_initially)
+ : fn_(fn)
+#ifdef FN_LAZY_FUNCTION_DEBUG_THREADS
+ ,
+ main_thread_id_(std::this_thread::get_id()),
+ allow_multi_threading_(allow_multi_threading_initially)
+#endif
{
}
@@ -323,16 +350,19 @@ inline void *Params::try_get_input_data_ptr(const int index) const
inline void *Params::try_get_input_data_ptr_or_request(const int index)
{
+ this->assert_valid_thread();
return this->try_get_input_data_ptr_or_request_impl(index);
}
inline void *Params::get_output_data_ptr(const int index)
{
+ this->assert_valid_thread();
return this->get_output_data_ptr_impl(index);
}
inline void Params::output_set(const int index)
{
+ this->assert_valid_thread();
this->output_set_impl(index);
}
@@ -348,18 +378,20 @@ inline ValueUsage Params::get_output_usage(const int index) const
inline void Params::set_input_unused(const int index)
{
+ this->assert_valid_thread();
this->set_input_unused_impl(index);
}
template<typename T> inline T Params::extract_input(const int index)
{
+ this->assert_valid_thread();
void *data = this->try_get_input_data_ptr(index);
BLI_assert(data != nullptr);
T return_value = std::move(*static_cast<T *>(data));
return return_value;
}
-template<typename T> inline const T &Params::get_input(const int index)
+template<typename T> inline const T &Params::get_input(const int index) const
{
const void *data = this->try_get_input_data_ptr(index);
BLI_assert(data != nullptr);
@@ -368,17 +400,43 @@ template<typename T> inline const T &Params::get_input(const int index)
template<typename T> inline T *Params::try_get_input_data_ptr_or_request(const int index)
{
+ this->assert_valid_thread();
return static_cast<T *>(this->try_get_input_data_ptr_or_request(index));
}
template<typename T> inline void Params::set_output(const int index, T &&value)
{
using DecayT = std::decay_t<T>;
+ this->assert_valid_thread();
void *data = this->get_output_data_ptr(index);
new (data) DecayT(std::forward<T>(value));
this->output_set(index);
}
+inline bool Params::try_enable_multi_threading()
+{
+ this->assert_valid_thread();
+ const bool success = this->try_enable_multi_threading_impl();
+#ifdef FN_LAZY_FUNCTION_DEBUG_THREADS
+ if (success) {
+ allow_multi_threading_ = true;
+ }
+#endif
+ return success;
+}
+
+inline void Params::assert_valid_thread() const
+{
+#ifdef FN_LAZY_FUNCTION_DEBUG_THREADS
+ if (allow_multi_threading_) {
+ return;
+ }
+ if (main_thread_id_ != std::this_thread::get_id()) {
+ BLI_assert_unreachable();
+ }
+#endif
+}
+
/** \} */
} // namespace blender::fn::lazy_function