wave4-native-disable-container-safety-restriction
Allow each parallel worker in IJobChunk to hold its own per-thread scratch NativeContainer by opting out of the safety system''s shared-container restriction.
- License 许可
- MIT
- 最近更新
- 2026-07-25
- Stars
- ★ 8
- Forks
- 0
01 前言 Front Matter
- name
- wave4-native-disable-container-safety-restriction
- tags
- [ "jobs", "native-containers" ]
- metadata
- { "tier": 3, "internal-only": true }
- description
- Allow each parallel worker in IJobChunk to hold its own per-thread scratch NativeContainer by opting out of the safety system''s shared-container restriction.
03 SKILL.md 正文
NativeDisableContainerSafetyRestriction — Per-Thread Scratch
Intent
Allow each parallel worker in IJobChunk to hold its own per-thread scratch NativeContainer by opting out of the safety system's shared-container restriction.
Use When
- IJobChunk needs per-chunk working memory (scratch buffer, priority queue, temporary list).
- Each chunk's
Execute()call receives a copy of the job struct, guaranteeing no sharing between workers.
Avoid When
- Container is truly shared across workers — use
NativeParallelMultiHashMap.AsParallelWriter()instead. - Using IJobParallelFor — job struct copy semantics differ; IJobChunk is safer for this pattern.
Senior Pattern
[BurstCompile]
public struct NearestNeighborJob : IJobChunk
{
// Per-thread ownership guaranteed by IJobChunk copy-per-chunk semantics.
// Safety restriction disabled because each worker has its own copy.
[NativeDisableContainerSafetyRestriction]
public NativePriorityHeap<float> Scratch;
[BurstCompile]
public void Execute(in ArchetypeChunk chunk, int unfilteredChunkIndex,
bool useEnableMask, in v128 chunkEnabledMask)
{
// Lazy init — Scratch is uninitialized on first Execute per chunk
if (!Scratch.IsCreated)
Scratch = new NativePriorityHeap<float>(16, Allocator.Temp);
var enumerator = new ChunkEntityEnumerator(useEnableMask, chunkEnabledMask, chunk.Count);
while (enumerator.NextEntityIndex(out var i))
{
Scratch.Push(/* distance for entity i */);
}
// Allocator.Temp — auto-disposed when job completes on this worker
}
}
Anti-Patterns
- Using
[NativeDisableContainerSafetyRestriction]on a container that IS shared between workers — silent race, impossible to detect in Burst release builds. - Forgetting
IsCreatedcheck — Burst-compiled null-ref crashes worker thread. - Using
Allocator.Persistentfor scratch — leaks if job is abandoned; useAllocator.Temp.
Runtime Risks
- Safety system cannot protect after opt-out — correctness depends entirely on developer's guarantee of per-thread ownership.
- IJobChunk guarantees one copy of job struct per chunk dispatch; IJobParallelFor does NOT give the same guarantee in all Unity versions.
Performance Notes
Allocator.Tempinside Burst job = thread-local storage, essentially free allocation.- Enables O(n) algorithms (nearest-neighbor, convex hull) without pre-allocated global arrays.
Architecture Guidance
IJobChunk guarantees per-chunk copy semantics — each worker thread receives its own copy of the job struct, so each worker has its own Scratch instance. This is why the opt-out is safe here specifically. Always document the per-thread ownership guarantee at the field declaration.
Related Skills
[[ijobchunk-full-anatomy]], [[ijobchunk-chunk-job]]
04 同仓库更多 Skills
dots-update-groups
How to choose the right ECS system group and ordering so per-frame and per-fixed-step work is deterministic and never races its own readers. Covers InitializationSystemGroup / SimulationSystemGroup / PresentationSystemGroup / FixedStepSimulationSystemGroup / VariableRateSimulationSystemGroup, UpdateBefore / UpdateAfter peer ordering, OrderFirst / OrderLast group-boundary placement, RateManager, and the cross-group ordering trap. Use when adding an ISystem, fixing "value visible one frame late" bugs, or coupling simulation to a fixed timestep.
dots-transform-patterns
The Entities 1.x transform model — LocalTransform (writable input) vs LocalToWorld (system-owned matrix), Parent/Child hierarchy, reparenting cost, uniform vs non-uniform scale (PostTransformMatrix), and when to opt out with custom transform systems. Use when designing parent/child hierarchies, runtime reparenting (mount/dismount/socket), or choosing transform components at the Baker boundary.
dots-singleton-patterns
Model cross-system shared configuration and game state as a single-entity component with a strict single-writer contract. Covers RequireForUpdate gating, SystemAPI.GetSingleton / GetSingletonRW / HasSingleton / TryGetSingleton, bake-time vs runtime-created vs ECB-system singletons, the "exactly one entity" runtime invariant, and the single-writer rule. Use when designing frame-stable global config, shared mutable state, or any component intended to exist on exactly one entity.
dots-hybrid-bridge
The one-way bridge between DOTS-owned runtime state and Unity-owned presentation. Covers UnityObjectRef for managed asset refs in components, the DOTS-writes / Unity-reads ownership rule, when to use managed IComponentData vs UnityObjectRef vs CompanionComponent, baker-bridge vs runtime-bridge, and SubScene boundary rules. Use when an entity must reference Unity assets (Mesh, Material, AudioClip, ScriptableObject), a MonoBehaviour view must read entity state, or input/UI must trigger ECS work.
dots-event-driven-ecs
Model one-frame events and external requests in ECS without dual ownership, polling, or persistent state leaks. Covers request-tag pattern with ECB, enableable command components (no structural change), event buffers (IBufferElementData), explicit consumer ownership, one-frame latency rules, and the banned C# event / UnityEvent / static bus anti-patterns. Use when input/UI/network must trigger ECS work, when a one-frame signal fans out to N consumers (damage, hit, collision), or when state changes must be processed exactly once.
valid_skill
A complete, well-formed test fixture skill for SkillHub validation testing. Covers basic task routing and code review for Unity projects.