Confusion about Input Dependencies

I’m running into some dependency issues, but I don’t understand why. Please take a look at the following test code:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Unity.Entities;
using Unity.Jobs;
using Unity.Burst;
using Unity.Collections;

public class ProducerSystemGroup : ComponentSystemGroup
{
}

[UpdateAfter(typeof(ProducerSystemGroup))]
public class ConsumerSystemGroup : ComponentSystemGroup
{
}

[UpdateInGroup(typeof(ProducerSystemGroup))]
public class ProducerSystem : JobComponentSystem
{
    private NativeMultiHashMap<int, int> countsByNumerMap;

    public NativeMultiHashMap<int, int> GetCountsByNumerMap()
    {
        return countsByNumerMap;
    }

    protected override void OnCreate()
    {
        countsByNumerMap = new NativeMultiHashMap<int, int>(10, Allocator.Persistent);
    }

    protected override void OnDestroy()
    {
        countsByNumerMap.Dispose();
    }

    protected override JobHandle OnUpdate(JobHandle inputDeps)
    {
        return new ProducerJob
        {
            countsByNumerMap = countsByNumerMap.AsParallelWriter()
        }
        .Schedule(inputDeps);
    }

    private struct ProducerJob : IJob
    {
        public NativeMultiHashMap<int, int>.ParallelWriter countsByNumerMap;

        public void Execute()
        {
            // write to map.
        }
    }
}

[UpdateInGroup(typeof(ConsumerSystemGroup))]
public class ConsumerSystem : JobComponentSystem
{
    private ProducerSystem producerSystem;

    protected override void OnCreate()
    {
        producerSystem = World.GetOrCreateSystem<ProducerSystem>();
    }

    protected override JobHandle OnUpdate(JobHandle inputDeps)
    {
        return new ConsumerJob
        {
            countsByNumerMap = producerSystem.GetCountsByNumerMap()
        }
        .Schedule(inputDeps);
    }

    private struct ConsumerJob : IJob
    {
        public NativeMultiHashMap<int, int> countsByNumerMap;

        public void Execute()
        {
            // read from map.
        }
    }
}

When run, I get the following error:

I was confused to see this, since from what I can tell, the dependency chain is set up correctly:

  1. ProducerSystem updates in ProducerSystemGroup.
  2. ConsumerSystem updates in ConsumerSystemGroup.
  3. ConsumerSystemGroup always updates after ProducerSystemGroup.

Wouldn’t that mean that ConsumerJob is guaranteed to be dependent on ProducerJob? Wouldn’t ProducerJob always complete before the scheduled ConsumerJob runs?

What am I missing here? Thanks for any help.

If consumer job does not read from any components that producer writes to, or does not write to any components that producer reads from, then Unity might try to be smart and believe there are no real dependencies that need to be passed in, which can be useful as it would allow multiple systems in sequence to schedule single-threaded jobs and those jobs could run in parallel to each other. However, if you don’t like this behavior, there is ENABLE_SIMPLE_SYSTEM_DEPENDENCIES as a define which removes this logic. However, I really recommend learning to always pass the JobHandle around when using NativeContainers (or use a library or framework that handles that for you) as this feature really helps remove bubbles in your job scheduling.

1 Like

That did the trick. I mirrored the ‘AddJobHandleForProducer’ API used by EntityCommandBufferSystems. Works fine now.

Thank you for the help! :slight_smile: