Search Unity

readonly is WriteOnly?

Discussion in 'Entity Component System' started by Nyarlathothep, Sep 13, 2018.

  1. Nyarlathothep

    Nyarlathothep

    Joined:
    Jun 13, 2013
    Posts:
    398
    I've been experimenting with the ECS today and seem to have discovered a bug involving the C# readonly keyword and the Job system safety checking. Apologies if this isn't the right place to make a bug report.

    I've created this fairly trivial system which simply runs through some input components, calculates a value from them and writes it to an output component (all inside a job). This is fine except that the _inputs field is only written to in the constructor, so as is usually good practice I marked it as readonly. I guessed this might even implicitly mark the field as [ReadOnly] for me which would be convenient.

    Instead I get this error (only when the _inputs field is readonly):

    InvalidOperationException: The native container has been declared as [WriteOnly] in the job, but you are reading from it.
    Here's an excerpt from the stacktrace:

    Unity.Entities.ComponentDataArray`1[T].get_Item (System.Int32 index) (at ComponentDataArray.cs:99)
    LightBulbPostSystem+AfterPower.Execute (System.Int32 index) (at LightBulbComponent.cs:76)
    Which shows it is happening on this line:


    var supply = _inputs[index].PowerSupplied;
    So the stacktrace makes sense, I am getting an item on this line. The safety check is even semi correct - I am reading from the field, but I never marked anything as WriteOnly!

    Why does adding readonly cause this?
     
    Last edited: Sep 13, 2018
  2. LukePammant

    LukePammant

    Joined:
    Mar 10, 2015
    Posts:
    50
    Did you ever figure this out? I'm getting the same issue.
     
  3. Joachim_Ante

    Joachim_Ante

    Unity Technologies

    Joined:
    Mar 16, 2005
    Posts:
    5,203
    Can you try removing [WriteOnly] from the first ComponentDataArray
     
  4. alexzzzz

    alexzzzz

    Joined:
    Nov 20, 2010
    Posts:
    1,447
    I had the same issue a while ago.
    readonly.png

    Removing the readonly modifiers (not the attributes) resolves the problem.
     
  5. Joachim_Ante

    Joachim_Ante

    Unity Technologies

    Joined:
    Mar 16, 2005
    Posts:
    5,203
    Please make a repro case in the form of a project folder that reproduces the issue. You can use bug reporter and then post case number here.
     
    Nyarlathothep likes this.
  6. Nyarlathothep

    Nyarlathothep

    Joined:
    Jun 13, 2013
    Posts:
    398
    I can't manage to replicate the problem now. Putting my gist example into a project doesn't produce it. I tried making the change to a similar system in the real project and it doesn't break either (although I've made fairly significant changes to the real project since the prototyping stage). If I encounter the problem again I'll try to replicate it in a smaller project.
     
  7. alexzzzz

    alexzzzz

    Joined:
    Nov 20, 2010
    Posts:
    1,447
    Can't reproduce it either. It's probably fixed by now.
     
  8. alexzzzz

    alexzzzz

    Joined:
    Nov 20, 2010
    Posts:
    1,447
    Reproduced. Case 1085026.
     
    Nyarlathothep likes this.
  9. Adam-Mechtley

    Adam-Mechtley

    Administrator

    Joined:
    Feb 5, 2007
    Posts:
    290
    Thanks! We'll take a look
     
  10. nttLIVE

    nttLIVE

    Joined:
    Sep 13, 2018
    Posts:
    80
    Is there any update on this?

    I'm getting this error while scheduling a job (ie: JobParallelFor1) where I pass a ArchetypeChunkSharedComponentType<SharedComponentX> where SharedComponentX is being read on another job (ie: JobParallelFor2). Note that I just pass it and schedule the job, the job (JobParallelFor1) has no logic and it will throw the error.

    InvalidOperationException: The native container has been declared as [WriteOnly] in the job, but you are reading from it.

    This error will point to the line where SharedComponentX is being read in the job (JobParallelFor2).
     
    Last edited: Oct 7, 2018
  11. nttLIVE

    nttLIVE

    Joined:
    Sep 13, 2018
    Posts:
    80
    If you use Injection to read a SharedComponent from a job and use Chunks on another job it will trigger the error. Using Chunks for both jobs fixed the problem.
     
    julian-moschuering likes this.
  12. Adam-Mechtley

    Adam-Mechtley

    Administrator

    Joined:
    Feb 5, 2007
    Posts:
    290
    Glad to hear you found a workaround for the time being! We unfortunately haven't had a chance to dig into this (or several other issues) due to Unite being right around the corner, but we'll be working through the backlog afterward.
     
  13. julian-moschuering

    julian-moschuering

    Joined:
    Apr 15, 2014
    Posts:
    529
    You are doing far too many Unites. One in Europe is enough. :)
     
    Sylmerria and Nyarlathothep like this.
  14. StefanWo

    StefanWo

    Joined:
    May 24, 2015
    Posts:
    122
    Had the same Bug. I created a NativeList inside of a jobs method and trying to access it via enumerator. This results in this strange exception. Solved it by using ToArray(allocator) instead...
     
    schaefsky likes this.
  15. schaefsky

    schaefsky

    Joined:
    Aug 11, 2013
    Posts:
    90
    I seem to have the same problem as StefanWo above. I have an editor tool script where I run a job like this_
    Code (CSharp):
    1. var testJob = new TestJob();
    2. testJob.Schedule().Complete();
    Inside the job there is a method with a local NativeList.
    Running this code gives me the error "InvalidOperationException: The Unity.Collections.NativeList`1[System.Int32] has been declared as [WriteOnly] in the job, but you are reading from it." when I Add() items to the local NativeList:
    Code (CSharp):
    1.  
    2.     public struct TestJob : IJob
    3.     {
    4.         public void Execute()
    5.         {
    6.             var list = new NativeList<int>(Allocator.Temp);
    7.             for (int i = 0; i < 10; i++)
    8.             {
    9.                 list.Add(i);
    10.             }
    11.  
    12.             DoLoop(list);
    13.         }
    14.  
    15.         private void DoLoop(NativeList<int> passedInList)
    16.         {
    17.             var localList = new NativeList<int>(Allocator.Temp);
    18.             foreach (var item in passedInList)
    19.             {
    20.                 Debug.Log($"DoLoop {item}");
    21.                 localList.Add(item);
    22.             }
    23.         }
    24.     }
    25.  
    Doing a passedInList.ToArray() at the foreach makes the error go away.
     
    Last edited: Jun 4, 2022