Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

[SOLVED] How to schedule iterative jobs?

Discussion in 'Entity Component System' started by John_Leorid, Sep 9, 2019.

  1. John_Leorid

    John_Leorid

    Joined:
    Nov 5, 2012
    Posts:
    646
    Currently I am working on a Job-System based "physics engine" but unlike unity-physics, I don't check any collisions, I just have a bunch of constraints, which can be used to measure the stress on a building.

    I want to schedule ~15x15 jobs, which then execute one after another until I get my result, but I always get the error:
    InvalidOperationException: The previously scheduled job FixedConstraintJob writes to the NativeArray FixedConstraintJob.lines. You must call JobHandle.Complete() on the job FixedConstraintJob, before you can read from the NativeArray safely.


    How to set the handles correctly in order to have one final handle to check "handle.IsCompleted" to know when the calculation is done?

    As far as I understood this, I can queue jobs and use the same arrays, in order to avoid unneccessary sync-frames on the main thread (where I would have to call Complete() ).

    So, is there a way to solve this? I can't call Complete() after every frame or even after every single job that has completed. That would be about 15x15 = 225+ frames for one calculation.

    Code (CSharp):
    1.  
    2. for (int i = 0; i < parameters.framesPerFrame; i++)
    3. {
    4.    /*
    5.        elements_N [Read & Write]
    6.    */
    7.    MoveAndRotateJob moveAndRotate = new MoveAndRotateJob(elements_N);
    8.    handle = moveAndRotate.Schedule(elements_N.Length, ilbc, handle);
    9.  
    10.    for (int ii = 0; ii < parameters.iterations; ii++)
    11.    {
    12.        /*
    13.            lines_N [Read & Write]
    14.            elements_N [ReadOnly]
    15.            globalRotation [ReadOnly]
    16.            multi [ReadOnly]
    17.            */
    18.        FixedConstraintJob constraintJob = new FixedConstraintJob(lines_N, elements_N,
    19.            transform.rotation, parameters.multi);
    20.        handle = constraintJob.Schedule(lines_N.Length, ilbc, handle);
    21.  
    22.        /*
    23.            lines_N [ReadOnly]
    24.            elements_N [Read & Write]
    25.            hashMap [ReadOnly]
    26.            */
    27.        ApplyNewPos posJob = new ApplyNewPos(lines_N, elements_N, hashMap);
    28.        handle = posJob.Schedule(elements_N.Length, ilbc, handle);
    29.  
    30.        /*
    31.            lines_N [ReadOnly]
    32.            elements_N [Read & Write]
    33.            hashMap [ReadOnly]
    34.            */
    35.        ApplyNewRot rotJob = new ApplyNewRot(lines_N, elements_N, hashMap);
    36.        handle = rotJob.Schedule(elements_N.Length, ilbc, handle);
    37.    }
    38. }
    39.  
     
  2. DreamingImLatios

    DreamingImLatios

    Joined:
    Jun 3, 2017
    Posts:
    4,223
    Your job chain looks correct, so the error is likely outside of the included code. Is this in a JobComponentSystem? A MonoBehaviour? Some other class?

    I'm guessing your error is due to you scheduling the jobs in the second frame before the first frame's jobs were completed. Call handle.Complete() before the for loop to make sure you don't infinitely chain jobs, or call handle.Complete right before rendering if you want the results to be up to date.
     
  3. John_Leorid

    John_Leorid

    Joined:
    Nov 5, 2012
    Posts:
    646
    This is part of a Monobehaviour.
    Actually, right above the code I reset the handle,
    handle = new JobHandle;

    So... whats the best way to debug this?

    PS: I am happy to hear that this should be possible in theory, so I just have to debug it and my physic engine will work. :D
     
  4. tertle

    tertle

    Joined:
    Jan 25, 2011
    Posts:
    3,753
    When are you calling complete?
     
  5. John_Leorid

    John_Leorid

    Joined:
    Nov 5, 2012
    Posts:
    646
    After the code above, I start a coroutine which checks:

    Code (CSharp):
    1.  
    2. if(!handle.IsComplete){
    3. yield return null;
    4. }
    5. handle.Complete();
    6. // do stuff with the arrays
    7. solving = false; // a variable to prevent solving when a calculation is running
     
  6. John_Leorid

    John_Leorid

    Joined:
    Nov 5, 2012
    Posts:
    646
    Okay, now I made a few tests.. Seems like it has nothing to do with the job code itself because I run an empty method:

    Code (CSharp):
    1. public struct FixedConstraintJob : IJobParallelFor
    2. {
    3.     public NativeArray<Line_S> lines;
    4.     [ReadOnly]
    5.     public NativeArray<Element_S> elements;
    6.     [ReadOnly]
    7.     public Quaternion globalRotation;
    8.     [ReadOnly]
    9.     public float multi;
    10.  
    11.     public FixedConstraintJob(NativeArray<Line_S> lines, NativeArray<Element_S> elements,
    12.         Quaternion globalRotation, float multi)
    13.     {
    14.         this.lines = lines;
    15.         this.elements = elements;
    16.         this.globalRotation = globalRotation;
    17.         this.multi = multi;
    18.     }
    19.  
    20.     public void Execute(int index)
    21.     { }
    22.     public void Lalala(int index)
    23.     {
    24.         // real code here, won't get executed
    25.     }
    26. }
    and still get the Error Message:
    InvalidOperationException: The previously scheduled job FixedConstraintJob writes to the NativeArray FixedConstraintJob.lines. You must call JobHandle.Complete() on the job FixedConstraintJob, before you can read from the NativeArray safely.


    So I guess this only checks for the attributes on top of the arrays when the job starts Executing ...
    I don't dispose or create any arrays when I create my jobs (what seems to be the cause of this error for most programmers)

    Any ideas?
     
  7. John_Leorid

    John_Leorid

    Joined:
    Nov 5, 2012
    Posts:
    646
    I feel so dumb right now, I was reading from the native array in the main thread during the calculation.
    So I just had to comment out the following lines, and the errors are gone. Everything works as it should (and the error message even directed me to those lines but I just ignored it and thought it was wrong because it was telling me that it has something to do with the FixedConstraints job .. stupid me)


    Code (CSharp):
    1. private void OnDrawGizmos()
    2. {
    3.     if (debug && debugMat)
    4.     {
    5.         DebugDrawElements();
    6.     }
    7.     if (debugDrawLines)
    8.     {
    9.         //foreach (Line_S l in lines_N)
    10.         //{
    11.             //Element_S elementA = elements_N[l.elementA];
    12.             //Element_S elementB = elements_N[l.elementB];
    13.  
    14.             //Gizmos.color = l.isDestroyed ? Color.red : Color.blue;
    15.  
    16.             //Gizmos.DrawLine(elementA.OrigPos, elementB.OrigPos);
    17.         //}
    18.     }
    19. }
     
    MostHated likes this.