a question about the Job System if you don’t mind. Am I correct if I say that the job system is able to work out the dependencies used by the jobs, but only if they are native arrays or other recognised data structures (which ones), so that jobs are executed safely and we don’t need to worry about thread safety?
I am a bit confused about thread safety is guaranteed, whenever possible, by the jobs, outside the ECS system.
Safety checks warn you about possible race conditions and if it not warn you, thus (in most cases but not in all) it’s safe (if you not disable any safety restrictions)
The safety system essentially cross checks read / write access of containers against the actual provided job dependencies. This is for both containers as well as component types in ECS which are internally represented with the same SafetyHandle system so from the job systems perspective ECS types appears as “containers”.
This lets us check all race conditions deterministically. At deploy time we can remove all checks and thus have zero overhead from the job debugger.
So beside the ecs container only native containers are checked, right? I am interested to know how these checks work outside the ECS provided containers
The C# job system supports Native Containers, guarantees safety with those. You can write your own native containers. Look for Unity.Collections for how they work and in the documentation. Other than that all data types are expected to be structs thus copied by value, thus inherently thread safe in C# jobs.
This is the recommended approach, it is the only thing we can and will gurantee thread safety for.
However there are situations where you want to leave the backdoor open and just do something that is unsafe and can not be validated. For this we have
This approach makes it so that the safety system simply pretends like those containers aren’t used by the job and also removes the checks from the containers. Same with unsafe pointer. This way at least all unsafe usage is declared, which means once you do get race conditions at least you can easily search for all possible places.
In the same way you can create a backdoor for class types too, using GCHandle. But of course using class types prevents you from using burst so that’s not recommended for both safety & performance reasons.
Thank you very much. I’ll read those links. I am trying to understand the best approach to write in to managed arrays of structs using burst. A pointer works fine but must be fixed of course and jobs won’t be able to check the safety.
I gave a look at this possible solution, but I noticed that the NativeArrayUnsafeUtility.
ConvertExistingDataToNativeArray still needs a pinned pointer. I need to find out if we have to pin ourselves and what/when is going to free it. I am working with the assumption that copy is not happening, but if it is happening I would like to understand when it happens (and when the data is going to be synchronized back)