零开销抽象

This commit is contained in:
2026-08-07 16:51:40 +08:00
parent 1e903dfe1e
commit 1ddd2799f2
8 changed files with 164 additions and 46 deletions
+1 -1
View File
@@ -121,7 +121,7 @@ This preserves normal C++ member semantics, keeps raw object access available wh
`Type_Descriptor<T>` describes the **type**. `Property_Object<T>` adds state and behavior to an **instance**. `Type_Descriptor<T>` describes the **type**. `Property_Object<T>` adds state and behavior to an **instance**.
The schema contains the registered property tuple, object defaults and the default synchronization plan. A `Property_Object<T>` resolves that plan for each instance and owns its lock topology and mutex storage. The schema contains the registered property tuple, object defaults and the default synchronization plan. `Property_Object<T>` shares one resolved default lock topology per type and keeps only instance synchronization state that is actually required: real mutex storage for locking policies and a compact override layout only when an instance explicitly supplies `Property_Synchronization`.
This distinction matters for performance and architecture: structural description is type-level information; managed synchronization is instance-level state. This distinction matters for performance and architecture: structural description is type-level information; managed synchronization is instance-level state.
+1 -1
View File
@@ -121,7 +121,7 @@ struct Device : Property_Object<Device> {
`Type_Descriptor<T>` 描述的是**类型**`Property_Object<T>` 管理的是**实例**。 `Type_Descriptor<T>` 描述的是**类型**`Property_Object<T>` 管理的是**实例**。
Schema 保存注册属性列表、对象默认 Attribute 和默认同步计划。`Property_Object<T>` 在每个实例上解析同步计划,并持有自己的锁拓扑和 mutex 存储 Schema 保存注册属性列表、对象默认 Attribute 和默认同步计划。`Property_Object<T>` 对同一类型共享一份解析后的默认 lock topology;实例只保留真正需要的同步状态:真实锁策略需要 mutex storage,只有显式传入 `Property_Synchronization` 的实例才额外持有紧凑的覆盖布局
这个边界必须长期保持:结构描述属于类型级;同步状态属于实例级。 这个边界必须长期保持:结构描述属于类型级;同步状态属于实例级。
@@ -42,6 +42,43 @@ template <class Policy>
concept Synchronization_Policy = requires { concept Synchronization_Policy = requires {
typename Policy::mutex_type; typename Policy::mutex_type;
} && Shared_Lockable<typename Policy::mutex_type>; } && Shared_Lockable<typename Policy::mutex_type>;
namespace detail {
template <class Mutex, bool Stores_Mutexes = !std::same_as<Mutex, Null_Shared_Mutex>>
class Mutex_Storage;
template <class Mutex>
class Mutex_Storage<Mutex, true> {
std::unique_ptr<Mutex[]> mutexes_;
public:
Mutex_Storage() = default;
explicit Mutex_Storage(std::size_t count) : mutexes_(count ? std::make_unique<Mutex[]>(count) : nullptr) {}
void reset(std::size_t count) {
mutexes_ = count ? std::make_unique<Mutex[]>(count) : nullptr;
}
Mutex& get(std::size_t index) noexcept {
return mutexes_[index];
}
Mutex& get(std::size_t index) const noexcept {
return mutexes_[index];
}
};
template <class Mutex>
class Mutex_Storage<Mutex, false> {
static Mutex& mutex() noexcept {
static Mutex value;
return value;
}
public:
Mutex_Storage() = default;
explicit Mutex_Storage(std::size_t) {}
void reset(std::size_t) {}
Mutex& get(std::size_t) noexcept {
return mutex();
}
Mutex& get(std::size_t) const noexcept {
return mutex();
}
};
}
enum class Managed_Access_Mode { enum class Managed_Access_Mode {
internal, internal,
external, external,
@@ -120,6 +157,8 @@ public:
using object_type = Derived; using object_type = Derived;
using mutex_type = typename Lock_Policy::mutex_type; using mutex_type = typename Lock_Policy::mutex_type;
private: private:
static constexpr bool uses_real_mutexes = !std::same_as<mutex_type, Null_Shared_Mutex>;
struct Empty_Guard_Locks {};
struct Dynamic_Lock_Targets { struct Dynamic_Lock_Targets {
std::vector<std::size_t> slots; std::vector<std::size_t> slots;
std::vector<std::size_t> unsynchronized_properties; std::vector<std::size_t> unsynchronized_properties;
@@ -131,23 +170,43 @@ private:
std::array<std::size_t, Capacity> unsynchronized_properties{}; std::array<std::size_t, Capacity> unsynchronized_properties{};
std::size_t unsynchronized_count{}; std::size_t unsynchronized_count{};
}; };
std::vector<std::size_t> lock_slots_; std::unique_ptr<std::size_t[]> custom_lock_layout_;
std::size_t lock_count_{}; [[no_unique_address]] detail::Mutex_Storage<mutex_type> mutex_storage_;
std::unique_ptr<mutex_type[]> locks_; static const auto& default_resolved_synchronization() {
static const auto resolved = resolve_synchronization_plan(type_descriptor<Derived>(), type_descriptor<Derived>().synchronization_plan());
return resolved;
}
template <class Schema> template <class Schema>
void initialize(const Schema& schema, const Synchronization_Plan& plan) { void initialize(const Schema& schema, const Synchronization_Plan& plan) {
auto resolved = resolve_synchronization_plan(schema, plan); auto resolved = resolve_synchronization_plan(schema, plan);
lock_slots_.assign(resolved.lock_slots.begin(), resolved.lock_slots.end()); auto layout = std::make_unique<std::size_t[]>(Schema::property_count + 1);
lock_count_ = resolved.lock_count; layout[0] = resolved.lock_count;
locks_ = lock_count_ ? std::make_unique<mutex_type[]>(lock_count_) : nullptr; std::copy(resolved.lock_slots.begin(), resolved.lock_slots.end(), layout.get() + 1);
custom_lock_layout_ = std::move(layout);
mutex_storage_.reset(resolved.lock_count);
} }
void copy_synchronization_from(const Property_Object& other) { void copy_synchronization_from(const Property_Object& other) {
lock_slots_ = other.lock_slots_; using Schema = type_descriptor_schema_t<Derived>;
lock_count_ = other.lock_count_; if (other.custom_lock_layout_) {
locks_ = lock_count_ ? std::make_unique<mutex_type[]>(lock_count_) : nullptr; auto layout = std::make_unique<std::size_t[]>(Schema::property_count + 1);
std::copy_n(other.custom_lock_layout_.get(), Schema::property_count + 1, layout.get());
custom_lock_layout_ = std::move(layout);
} else {
custom_lock_layout_.reset();
}
mutex_storage_.reset(lock_count());
}
std::size_t lock_count() const noexcept {
return custom_lock_layout_ ? custom_lock_layout_[0] : default_resolved_synchronization().lock_count;
} }
std::size_t slot(std::size_t index) const noexcept { std::size_t slot(std::size_t index) const noexcept {
return lock_slots_[index]; return custom_lock_layout_ ? custom_lock_layout_[index + 1] : default_resolved_synchronization().slot(index);
}
mutex_type& mutex(std::size_t index) noexcept {
return mutex_storage_.get(index);
}
mutex_type& mutex(std::size_t index) const noexcept {
return mutex_storage_.get(index);
} }
template <std::size_t Capacity> template <std::size_t Capacity>
static void sort_unique_prefix(std::array<std::size_t, Capacity>& values, std::size_t& count) { static void sort_unique_prefix(std::array<std::size_t, Capacity>& values, std::size_t& count) {
@@ -303,25 +362,36 @@ private:
auto read_one() const { auto read_one() const {
using Schema = type_descriptor_schema_t<Derived>; using Schema = type_descriptor_schema_t<Derived>;
static_assert(property_read_allowed_v<Mode, Schema, Index>); static_assert(property_read_allowed_v<Mode, Schema, Index>);
using Value = typename Schema::template property_type<Index>::value_type; using Property = typename Schema::template property_type<Index>;
using Value = typename Property::value_type;
if constexpr (!uses_real_mutexes && !Property::accessor_type::synchronized_view_read) {
return Value(read_unlocked<Index>(*this));
}
auto lock_slot = slot(Index); auto lock_slot = slot(Index);
Single_Read_View<Mode> view{*this, Index, lock_slot}; Single_Read_View<Mode> view{*this, Index, lock_slot};
if constexpr (!uses_real_mutexes) {
return Value(read_unlocked<Index>(view));
}
if (lock_slot == Resolved_Synchronization_View::unsynchronized_slot) { if (lock_slot == Resolved_Synchronization_View::unsynchronized_slot) {
return Value(read_unlocked<Index>(view)); return Value(read_unlocked<Index>(view));
} }
std::shared_lock lock{locks_[lock_slot]}; std::shared_lock lock{mutex(lock_slot)};
return Value(read_unlocked<Index>(view)); return Value(read_unlocked<Index>(view));
} }
template <Managed_Access_Mode Mode, std::size_t Index, class Value> template <Managed_Access_Mode Mode, std::size_t Index, class Value>
void write_one(Value&& value) { void write_one(Value&& value) {
using Schema = type_descriptor_schema_t<Derived>; using Schema = type_descriptor_schema_t<Derived>;
static_assert(property_write_allowed_v<Mode, Schema, Index>); static_assert(property_write_allowed_v<Mode, Schema, Index>);
if constexpr (!uses_real_mutexes) {
write_unlocked<Index>(std::forward<Value>(value));
return;
}
auto lock_slot = slot(Index); auto lock_slot = slot(Index);
if (lock_slot == Resolved_Synchronization_View::unsynchronized_slot) { if (lock_slot == Resolved_Synchronization_View::unsynchronized_slot) {
write_unlocked<Index>(std::forward<Value>(value)); write_unlocked<Index>(std::forward<Value>(value));
return; return;
} }
std::unique_lock lock{locks_[lock_slot]}; std::unique_lock lock{mutex(lock_slot)};
write_unlocked<Index>(std::forward<Value>(value)); write_unlocked<Index>(std::forward<Value>(value));
} }
public: public:
@@ -330,7 +400,7 @@ public:
const Property_Object* owner_{}; const Property_Object* owner_{};
std::vector<std::size_t> slots_; std::vector<std::size_t> slots_;
std::vector<std::size_t> unsynchronized_properties_; std::vector<std::size_t> unsynchronized_properties_;
std::vector<std::shared_lock<mutex_type>> locks_; [[no_unique_address]] std::conditional_t<uses_real_mutexes, std::vector<std::shared_lock<mutex_type>>, Empty_Guard_Locks> locks_;
bool holds(std::size_t index) const { bool holds(std::size_t index) const {
auto lock_slot = owner_->slot(index); auto lock_slot = owner_->slot(index);
if (lock_slot == Resolved_Synchronization_View::unsynchronized_slot) { if (lock_slot == Resolved_Synchronization_View::unsynchronized_slot) {
@@ -340,9 +410,11 @@ public:
} }
friend class Property_Object; friend class Property_Object;
Read_Guard(const Property_Object& owner, Dynamic_Lock_Targets targets) : owner_(&owner), slots_(std::move(targets.slots)), unsynchronized_properties_(std::move(targets.unsynchronized_properties)) { Read_Guard(const Property_Object& owner, Dynamic_Lock_Targets targets) : owner_(&owner), slots_(std::move(targets.slots)), unsynchronized_properties_(std::move(targets.unsynchronized_properties)) {
locks_.reserve(slots_.size()); if constexpr (uses_real_mutexes) {
for (auto lock_slot : slots_) { locks_.reserve(slots_.size());
locks_.emplace_back(owner_->locks_[lock_slot]); for (auto lock_slot : slots_) {
locks_.emplace_back(owner_->mutex(lock_slot));
}
} }
} }
public: public:
@@ -376,7 +448,7 @@ public:
Property_Object* owner_{}; Property_Object* owner_{};
std::vector<std::size_t> slots_; std::vector<std::size_t> slots_;
std::vector<std::size_t> unsynchronized_properties_; std::vector<std::size_t> unsynchronized_properties_;
std::vector<std::unique_lock<mutex_type>> locks_; [[no_unique_address]] std::conditional_t<uses_real_mutexes, std::vector<std::unique_lock<mutex_type>>, Empty_Guard_Locks> locks_;
bool holds(std::size_t index) const { bool holds(std::size_t index) const {
auto lock_slot = owner_->slot(index); auto lock_slot = owner_->slot(index);
if (lock_slot == Resolved_Synchronization_View::unsynchronized_slot) { if (lock_slot == Resolved_Synchronization_View::unsynchronized_slot) {
@@ -386,9 +458,11 @@ public:
} }
friend class Property_Object; friend class Property_Object;
Write_Guard(Property_Object& owner, Dynamic_Lock_Targets targets) : owner_(&owner), slots_(std::move(targets.slots)), unsynchronized_properties_(std::move(targets.unsynchronized_properties)) { Write_Guard(Property_Object& owner, Dynamic_Lock_Targets targets) : owner_(&owner), slots_(std::move(targets.slots)), unsynchronized_properties_(std::move(targets.unsynchronized_properties)) {
locks_.reserve(slots_.size()); if constexpr (uses_real_mutexes) {
for (auto lock_slot : slots_) { locks_.reserve(slots_.size());
locks_.emplace_back(owner_->locks_[lock_slot]); for (auto lock_slot : slots_) {
locks_.emplace_back(owner_->mutex(lock_slot));
}
} }
} }
public: public:
@@ -445,7 +519,7 @@ public:
class Static_Read_Guard { class Static_Read_Guard {
const Property_Object* owner_{}; const Property_Object* owner_{};
Static_Lock_Targets<Capacity> targets_; Static_Lock_Targets<Capacity> targets_;
std::array<std::shared_lock<mutex_type>, Capacity> locks_{}; [[no_unique_address]] std::conditional_t<uses_real_mutexes, std::array<std::shared_lock<mutex_type>, Capacity>, Empty_Guard_Locks> locks_{};
bool holds(std::size_t index) const { bool holds(std::size_t index) const {
auto lock_slot = owner_->slot(index); auto lock_slot = owner_->slot(index);
if (lock_slot == Resolved_Synchronization_View::unsynchronized_slot) { if (lock_slot == Resolved_Synchronization_View::unsynchronized_slot) {
@@ -455,8 +529,10 @@ public:
} }
friend class Property_Object; friend class Property_Object;
Static_Read_Guard(const Property_Object& owner, Static_Lock_Targets<Capacity> targets) : owner_(&owner), targets_(std::move(targets)) { Static_Read_Guard(const Property_Object& owner, Static_Lock_Targets<Capacity> targets) : owner_(&owner), targets_(std::move(targets)) {
for (std::size_t index = 0; index < targets_.slot_count; ++index) { if constexpr (uses_real_mutexes) {
locks_[index] = std::shared_lock<mutex_type>{owner_->locks_[targets_.slots[index]]}; for (std::size_t index = 0; index < targets_.slot_count; ++index) {
locks_[index] = std::shared_lock<mutex_type>{owner_->mutex(targets_.slots[index])};
}
} }
} }
public: public:
@@ -489,7 +565,7 @@ public:
class Static_Write_Guard { class Static_Write_Guard {
Property_Object* owner_{}; Property_Object* owner_{};
Static_Lock_Targets<Capacity> targets_; Static_Lock_Targets<Capacity> targets_;
std::array<std::unique_lock<mutex_type>, Capacity> locks_{}; [[no_unique_address]] std::conditional_t<uses_real_mutexes, std::array<std::unique_lock<mutex_type>, Capacity>, Empty_Guard_Locks> locks_{};
bool holds(std::size_t index) const { bool holds(std::size_t index) const {
auto lock_slot = owner_->slot(index); auto lock_slot = owner_->slot(index);
if (lock_slot == Resolved_Synchronization_View::unsynchronized_slot) { if (lock_slot == Resolved_Synchronization_View::unsynchronized_slot) {
@@ -499,8 +575,10 @@ public:
} }
friend class Property_Object; friend class Property_Object;
Static_Write_Guard(Property_Object& owner, Static_Lock_Targets<Capacity> targets) : owner_(&owner), targets_(std::move(targets)) { Static_Write_Guard(Property_Object& owner, Static_Lock_Targets<Capacity> targets) : owner_(&owner), targets_(std::move(targets)) {
for (std::size_t index = 0; index < targets_.slot_count; ++index) { if constexpr (uses_real_mutexes) {
locks_[index] = std::unique_lock<mutex_type>{owner_->locks_[targets_.slots[index]]}; for (std::size_t index = 0; index < targets_.slot_count; ++index) {
locks_[index] = std::unique_lock<mutex_type>{owner_->mutex(targets_.slots[index])};
}
} }
} }
public: public:
@@ -617,10 +695,12 @@ private:
callback(context, property_index, key, typeid(Value), std::addressof(value)); callback(context, property_index, key, typeid(Value), std::addressof(value));
} }
}; };
if (lock_slot == Resolved_Synchronization_View::unsynchronized_slot) { if constexpr (!uses_real_mutexes) {
emit();
} else if (lock_slot == Resolved_Synchronization_View::unsynchronized_slot) {
emit(); emit();
} else { } else {
std::shared_lock lock{locks_[lock_slot]}; std::shared_lock lock{mutex(lock_slot)};
emit(); emit();
} }
result = Runtime_Access_Result::ok; result = Runtime_Access_Result::ok;
@@ -688,10 +768,7 @@ private:
return &value; return &value;
} }
protected: protected:
Property_Object() : Property_Object_Base(runtime_interface()) { Property_Object() : Property_Object_Base(runtime_interface()), mutex_storage_(default_resolved_synchronization().lock_count) {}
const auto& schema = type_descriptor<Derived>();
initialize(schema, schema.synchronization_plan());
}
explicit Property_Object(Property_Synchronization synchronization) : Property_Object_Base(runtime_interface()) { explicit Property_Object(Property_Synchronization synchronization) : Property_Object_Base(runtime_interface()) {
initialize(type_descriptor<Derived>(), synchronization.plan); initialize(type_descriptor<Derived>(), synchronization.plan);
} }
@@ -713,7 +790,12 @@ public:
return type_descriptor<Derived>(); return type_descriptor<Derived>();
} }
Resolved_Synchronization_View resolved_synchronization() const noexcept { Resolved_Synchronization_View resolved_synchronization() const noexcept {
return {lock_slots_, lock_count_}; using Schema = type_descriptor_schema_t<Derived>;
if (custom_lock_layout_) {
return {{custom_lock_layout_.get() + 1, Schema::property_count}, custom_lock_layout_[0]};
}
const auto& resolved = default_resolved_synchronization();
return {resolved.lock_slots, resolved.lock_count};
} }
Derived& unsafe_object() noexcept { Derived& unsafe_object() noexcept {
return static_cast<Derived&>(*this); return static_cast<Derived&>(*this);
+34
View File
@@ -74,6 +74,25 @@ struct structive::Type_Descriptor<Non_Copyable_Device> {
); );
} }
}; };
struct Lockless_Device : Property_Object<Lockless_Device, No_Lock_Policy> {
Lockless_Device() = default;
explicit Lockless_Device(Property_Synchronization synchronization) : Property_Object(std::move(synchronization)) {}
int left{1};
int right{2};
};
template <>
struct structive::Type_Descriptor<Lockless_Device> {
static auto get() {
return object<Lockless_Device>(
synchronization(sync_all_independent, sync_group("sum", "left", "right", "sum")),
field < &Lockless_Device::left > (key < "left" >),
field < &Lockless_Device::right > (key < "right" >),
computed_property<Lockless_Device, int>([](const auto& view) {
return view.template get<&Lockless_Device::left>() + view.template get<&Lockless_Device::right>();
}, key < "sum" >)
);
}
};
template <class View> template <class View>
concept Has_Write_Temperature = requires(View view) { concept Has_Write_Temperature = requires(View view) {
view.template write<&Device::temperature>(1); view.template write<&Device::temperature>(1);
@@ -124,6 +143,14 @@ int main() {
REQUIRE(shared_device.lock_slot<&Device::pressure>() == shared_device.lock_slot<&Device::min_speed>()); REQUIRE(shared_device.lock_slot<&Device::pressure>() == shared_device.lock_slot<&Device::min_speed>());
Device grouped_device{property_synchronization<Device>(synchronization(sync_all_independent, sync_group < &Device::temperature, &Device::pressure > ("environment")))}; Device grouped_device{property_synchronization<Device>(synchronization(sync_all_independent, sync_group < &Device::temperature, &Device::pressure > ("environment")))};
REQUIRE(grouped_device.lock_slot<&Device::temperature>() == grouped_device.lock_slot<&Device::pressure>()); REQUIRE(grouped_device.lock_slot<&Device::temperature>() == grouped_device.lock_slot<&Device::pressure>());
Device shared_copy{shared_device};
REQUIRE(shared_copy.lock_slot<&Device::temperature>() == shared_copy.lock_slot<&Device::pressure>());
Device shared_move{std::move(shared_copy)};
REQUIRE(shared_move.lock_slot<&Device::temperature>() == shared_move.lock_slot<&Device::pressure>());
Device assignment_target;
auto assignment_target_slot = assignment_target.lock_slot<&Device::pressure>();
assignment_target = shared_device;
REQUIRE(assignment_target.lock_slot<&Device::pressure>() == assignment_target_slot);
device.external().write < &Device::temperature > (30); device.external().write < &Device::temperature > (30);
REQUIRE(device.external().read<&Device::temperature>() == 30); REQUIRE(device.external().read<&Device::temperature>() == 30);
device.persistence().load < &Device::pressure > (101); device.persistence().load < &Device::pressure > (101);
@@ -151,6 +178,13 @@ int main() {
REQUIRE(computed.external().read_key<"speed_span">() == 90); REQUIRE(computed.external().read_key<"speed_span">() == 90);
computed.write < &Computed_Device::min_speed > (20); computed.write < &Computed_Device::min_speed > (20);
REQUIRE(computed.external().read_key<"speed_span">() == 80); REQUIRE(computed.external().read_key<"speed_span">() == 80);
Lockless_Device lockless;
REQUIRE(lockless.read<&Lockless_Device::left>() == 1);
lockless.write < &Lockless_Device::right > (4);
REQUIRE(lockless.read_key<"sum">() == 5);
auto lockless_guard = lockless.lock_shared<&Lockless_Device::left, &Lockless_Device::right>();
REQUIRE(lockless_guard.get<&Lockless_Device::left>() == 1);
REQUIRE(lockless_guard.get<&Lockless_Device::right>() == 4);
Non_Copyable_Device non_copyable; Non_Copyable_Device non_copyable;
bool non_copyable_visited = false; bool non_copyable_visited = false;
non_copyable.external().for_each_readable_locked([&](auto, const auto&, const auto& value) { non_copyable.external().for_each_readable_locked([&](auto, const auto&, const auto& value) {
+2 -2
View File
@@ -407,7 +407,7 @@ auto policy = property_synchronization<Device>(
); );
``` ```
The schema remains the same; only the instance lock topology changes. The schema remains the same; only that instance uses an override lock topology. Default instances share one resolved topology per type, so the default plan is not re-resolved for every object.
## 15. Inspect resolved synchronization ## 15. Inspect resolved synchronization
@@ -628,7 +628,7 @@ struct Device : Property_Object<Device, No_Lock_Policy> {
}; };
``` ```
`No_Lock_Policy` uses `Null_Shared_Mutex`; it removes real mutual exclusion and should only be selected when external ownership guarantees make that correct. `No_Lock_Policy` uses `Null_Shared_Mutex`; it removes real mutual exclusion and should only be selected when external ownership guarantees make that correct. Its default managed-object path stores no mutex array and performs no per-instance heap allocation for synchronization. A custom `Property_Synchronization` may still allocate a compact override topology because computed-property synchronization-domain checks must preserve the selected per-instance layout.
## 23. Raw object access ## 23. Raw object access
+2 -2
View File
@@ -407,7 +407,7 @@ auto policy = property_synchronization<Device>(
); );
``` ```
Schema 本身不变,只改变该实例的 lock topology。 Schema 本身不变,只有这个实例使用覆盖后的 lock topology。默认实例按类型共享一份解析结果,因此不会为每个对象重复解析默认同步计划。
## 15. 查看解析后的同步拓扑 ## 15. 查看解析后的同步拓扑
@@ -628,7 +628,7 @@ struct Device : Property_Object<Device, No_Lock_Policy> {
}; };
``` ```
`No_Lock_Policy` 使用 `Null_Shared_Mutex`,它取消真实互斥;只有外部所有权规则能够保证正确性时才应该使用。 `No_Lock_Policy` 使用 `Null_Shared_Mutex`,它取消真实互斥;只有外部所有权规则能够保证正确性时才应该使用。默认 managed-object 路径不保存 mutex 数组,也不会为同步状态产生每实例堆分配。显式使用自定义 `Property_Synchronization` 时仍可能分配一份紧凑覆盖 topology,因为 computed property 的同步域检查必须保留该实例选择的布局。
## 23. Raw Object Access ## 23. Raw Object Access
+4 -3
View File
@@ -72,8 +72,9 @@ This is the structural definition of the type.
`Property_Object<T>` provides: `Property_Object<T>` provides:
- resolved lock-slot topology; - a type-shared resolved default lock-slot topology;
- per-instance mutex storage; - per-instance mutex storage only when the selected lock policy requires real mutexes;
- a compact per-instance topology only for explicit synchronization overrides;
- managed typed reads and writes; - managed typed reads and writes;
- capability views; - capability views;
- static and runtime multi-property guards; - static and runtime multi-property guards;
@@ -84,7 +85,7 @@ This is instance behavior, not schema identity.
### 3.3 Design rule ### 3.3 Design rule
Do not move instance state into the schema, and do not make schema metadata depend on one particular instance-management policy. Do not move mutable instance synchronization state into the schema, and do not make schema metadata depend on one particular instance-management policy. Immutable topology derived from the type-level default plan may be shared across all instances of that type.
A future user may want to describe a large number of plain objects without paying per-object synchronization cost. The architecture should continue to leave that possibility open. A future user may want to describe a large number of plain objects without paying per-object synchronization cost. The architecture should continue to leave that possibility open.
+4 -3
View File
@@ -72,8 +72,9 @@ Structive 把类型级描述和实例级管理分开。
`Property_Object<T>` 提供: `Property_Object<T>` 提供:
- 解析后的 lock slot 拓扑; - 同一类型共享的默认解析 lock slot 拓扑;
- 每实例 mutex 存储; - 只有真实锁策略才需要的每实例 mutex 存储;
- 只有显式同步覆盖实例才持有的紧凑 topology;
- managed typed read/write - managed typed read/write
- capability view - capability view
- 静态与运行时多属性 guard - 静态与运行时多属性 guard
@@ -84,7 +85,7 @@ Structive 把类型级描述和实例级管理分开。
### 3.3 设计约束 ### 3.3 设计约束
不要把实例状态塞进 Schema,也不要让 Schema 必须依赖某一种特定的实例管理策略。 不要把可变的实例同步状态塞进 Schema,也不要让 Schema 必须依赖某一种特定的实例管理策略。由类型级默认同步计划推导出的不可变 topology 可以由同类型所有实例共享。
以后完全可能有用户只想描述大量普通对象,却不愿意为每个对象承担同步状态成本。当前架构应该持续保留这种可能性。 以后完全可能有用户只想描述大量普通对象,却不愿意为每个对象承担同步状态成本。当前架构应该持续保留这种可能性。