How to fix a race condition between these 2 systems

I have made these two systems to enable/disable the gameObjects. is there any way to solve the race condition without calling JobHandle.Complete() on the first job

public class RenderOnOffEntitiesSystem : SystemBase
{

    protected override void OnUpdate()
    {
 

   
        Matrix4x4 V = Camera.main.worldToCameraMatrix;
        Matrix4x4 P = Camera.main.projectionMatrix;
        Matrix4x4 MVP = P * V;
        float3 cameraPos = Camera.main.transform.position;

        Entities.ForEach((ref renderEnabledCo renderEnabledCo, in LocalToWorld localToWorld) =>
            {

                float3 screenPos = MVP.MultiplyPoint(localToWorld.Position);
                Vector2 screenPoint = new Vector2(screenPos.x + 1f, screenPos.y + 1f) * 0.5f;

                if (screenPoint.x < 0 || screenPoint.x > 1 || screenPoint.y < 0 || screenPoint.y > 1 || math.distancesq(localToWorld.Position, cameraPos) > 1900 /*35*/)
                {

                    renderEnabledCo.Enabled = false;

                }
                else
                {
                    renderEnabledCo.Enabled = true;

                }


            }).ScheduleParallel();




    }
}

system 2

public class RenderOnOffObjectsSystem : SystemBase
{

    private EntityQuery entities;
    protected override void OnCreate()
    {
        EntityQueryDesc entitiesQueryDesc = new EntityQueryDesc
        {
            All = new ComponentType[] { typeof(renderTag) }
        };

        entities = GetEntityQuery(entitiesQueryDesc);
    }
    protected override void OnUpdate()
    {

        var renderEnabledCoType = GetArchetypeChunkComponentType<renderEnabledCo>(true);
        var RenderIndexCoType = GetArchetypeChunkComponentType<RenderIndexCo>(true);
        var entitiesChunks = entities.CreateArchetypeChunkArray(Allocator.TempJob);
   
        var gameobjects = GMSingleton.Singleton.gameobjects.ToArray();

        for (int c = 0; c < entitiesChunks.Length; c++)
        {
            var chunk = entitiesChunks[c];

            var renderEnabledCos = chunk.GetNativeArray(renderEnabledCoType);
            var RenderIndexCos = chunk.GetNativeArray(RenderIndexCoType);
       

            for (int i = 0; i < chunk.Count; i++)
            {
                    if (renderEnabledCos[i].Enabled )
                    {
                    
                        gameobjects[RenderIndexCos[i].value].SetActive(true);
                    
                    }
                    else
                    {
                        gameobjects[RenderIndexCos[i].value].SetActive(false);
                  
                    }
            }
        
        }
        entitiesChunks.Dispose();
    }
}

You have a job that writes to renderEnabledCo. And then later you want to read from that component on the main thread. Therefore, you must complete that job, probably in the second system via CompleteDependency().

1 Like

Depending on what you are trying to do you may want to set your update order see.

https://docs.unity3d.com/Packages/com.unity.entities@1.0/manual/systems-update-order.html

1 Like

Yes that is the problem so I get an error

I am looking for something similar to LambdaJobDescriptionConstructionMethods like :
WithNativeDisableContainerSafetyRestriction.
WithNativeDisableParallelForRestriction.
WithNativeDisableUnsafePtrRestriction.

however when I use Entities.ForEach.Run() in the second system the race condition error doesn’t occur what is actually happening here so the problem is solved automatically ?

public class RenderOnOffObjectsSystem : SystemBase
{

    protected override void OnUpdate()
    {
        var gameobjects = GMSingleton.Singleton.gameobjects.ToArray();

        Entities.WithoutBurst().ForEach((in renderEnabledCo renderEnabledCo, in RenderIndexCo renderIndexCo) =>

        {

            if (renderEnabledCo.Enabled)
            {
                gameobjects[renderIndexCo.value].SetActive(true);
            }
            else
            {
                gameobjects[renderIndexCo.value].SetActive(false);
            }

        }).Run();

    }
}

Entities.ForEach().Run() completes the JobHandle behind the scenes.

1 Like

aha i see thank you! i also have this System

public class AttackSystem : SystemBase
{
    protected override void OnUpdate()
    {

        ComponentDataFromEntity<LocalToWorld> LocalToWorlds = GetComponentDataFromEntity<LocalToWorld>(true);
        BufferFromEntity<dmBufferBufferElement> dmBuffer = GetBufferFromEntity<dmBufferBufferElement>();

        Entities.WithReadOnly(LocalToWorlds).WithNativeDisableParallelForRestriction(dmBufferElements)
            .ForEach((Entity entity,in ReferencesComponent references) =>
            {

                            float distance = math.distance(LocalToWorlds[entity].Position, LocalToWorlds[references.enemy].Position);

                            if (distance <= 5)
                            {
                               dmBuffer[references.enemy].Add(new dmBufferBufferElement { value = 1 });
                            }

            }).ScheduleParallel();
    }
}

I would like to ask if it is safe to add BufferElements like so in Parallel, and Is it safe to read or write from ComponentDataFromEntity inside Entities.ForEach, I mean will the system add this to the dependency to complete the JobHandle to avoid race condition in the other systems?

If the dynamic buffer was a ref argument in your ForEach(), adding would for sure be safe. However, since you are using a lookup (is there a reason you are still on Entities 0.51?), you yourself have to be sure that no two threads can touch the same dynamic buffer at the same time. Otherwise, a race condition could cause a hard crash on rare occasions.

Reading lookups inside an Entities.ForEach in pretty much always safe. Writing is allowed in non-parallel jobs by default, but you have to be more careful with parallel jobs (by default the safety system will scream at you).

1 Like

Yes, actually i have a project that I tried to upgrade it to (Unity 2022) and (Dots 1) and (URP) and (hybrid renderer v2) without changing anything, i just updated the materials to URP and i also disabled all the systems but the frame rate dropped from 300 fps to 180 just because of the render

You are on built-in? That must be a really old version. It is worth noting that prior to 2022.2 beta 15 that there was a significant rendering performance regression. But now it outperforms URP in 2021 with HR V2 in every benchmark I have thrown at it. If you are seeing a difference in builds (forget comparing in the editor, there’s a lot more Entities tooling in 2022.2), I would suspect that would be due to the shaders themselves. HR V1 had major issues with main thread performance with dynamic entities.

2 Likes

Yes I read that it is faster and more optimized, but I think it is something related to my project because I am still using GameObjects for render, and entities just for logic, so (i guess) any system related to entities graphic or render is just waste of cpu for my project, also, I ran into another problem, which is converting components because i have a lot of entities and i’m using [GenerateAuthoringComponent] then setting values in inspector.