Search Unity

Bug Using IJobEntity.Run() or IJobChunk.Run() triggers SafetyCheck. Bug?

Discussion in 'Entity Component System' started by Dechichi01, Dec 25, 2022.

  1. Dechichi01

    Dechichi01

    Joined:
    Jun 5, 2016
    Posts:
    39
    I personally prefer using IJobEntity over the idiomatic foreach, as I find it to be more readable/maintainable. However, when I use .Run(), which I expected would run the job in place on the main thread, I get safety system related exceptions from jobs that write to queried components. Using .Schedule() gets rid of the problem, but then I'm paying the price of scheduling.

    Here's an example derived from the Netcode samples, but using IJobEntity (this behavior is not exclusive to Netcode):

    Code (CSharp):
    1.     [WorldSystemFilter(WorldSystemFilterFlags.ServerSimulation)]
    2.     [UpdateInGroup(typeof(InitializationSystemGroup), OrderFirst = true)]
    3.     [BurstCompile]
    4.     [RequireMatchingQueriesForUpdate]
    5.     public partial struct GoInGameServerSystem : ISystem
    6.     {
    7.         public void OnCreate(ref SystemState state)
    8.         {
    9.         }
    10.  
    11.         public void OnDestroy(ref SystemState state)
    12.         {
    13.         }
    14.  
    15.         [BurstCompile]
    16.         public void OnUpdate(ref SystemState state)
    17.         {
    18.             new ProcessGoInGameRpcJob
    19.             {
    20.                 Ecb = SystemAPI.GetSingleton<EndInitializationEntityCommandBufferSystem.Singleton>()
    21.                     .CreateCommandBuffer(state.WorldUnmanaged)
    22.             }.Run();
    23.         }
    24.  
    25.         [WithAll(typeof(GoInGameRequest))]
    26.         partial struct ProcessGoInGameRpcJob : IJobEntity
    27.         {
    28.             public EntityCommandBuffer Ecb;
    29.  
    30.             public void Execute(Entity rpcEntity, in ReceiveRpcCommandRequestComponent rpc)
    31.             {
    32.                 var connectionEntity = rpc.SourceConnection;
    33.                 Ecb.AddComponent<NetworkStreamInGame>(connectionEntity);
    34.                 Ecb.DestroyEntity(rpcEntity);
    35.             }
    36.         }
    37.     }
    Which gives the following exception, from WarnAboutStaleRpcSystem, which writes to one of the queried components:

    upload_2022-12-25_14-27-26.png


    Is that a bug, or is the alternative I'm looking for not supported? If it's the latter, what is the purpose of Run() given that it breaks with such a simple use case?
     
  2. eizenhorn

    eizenhorn

    Joined:
    Oct 17, 2016
    Posts:
    2,684
    You should complete previous type dependency chain you want to read from main thread, as it's scheduled somewhere before and can write at any time and if you at the same time will try to read from the same memory (component) on main thread - it will be pure race condition from which safety system is protects you.

    With burst compiled ISystem OnUpdate - that cost is neglectable
     
    Last edited: Dec 28, 2022
    Dechichi01 likes this.
  3. DreamingImLatios

    DreamingImLatios

    Joined:
    Jun 3, 2017
    Posts:
    4,264
    With Entities.ForEach().Run(), Dependency is automatically completed. However, I don't think that is the case with IJobEntity.Run().
     
    Occuros and Dechichi01 like this.
  4. Dechichi01

    Dechichi01

    Joined:
    Jun 5, 2016
    Posts:
    39
    Thanks, and turns out the codegen for the idiomatic for each complete dependencies as well, I missed that the first time I looked. Thanks for the clarification @eizenhorn and @DreamingImLatios