Version: Unity 7.0 Alpha (7000.0)
Language : English
Thread safe types
Implement a custom native container

Introduction to NativeContainer

NativeContainer is a thread-safe C# wrapper for native memory. NativeContainer objects also allow a job to access data shared with the main thread rather than working with a copy.

The Unity.Collections namespace contains several NativeContainer objects. For a full list of the types available, refer to Collection types reference.

Read and write access

By default, when a job has access to a NativeContainer instance, it has both read and write access. This configuration can slow performance. This is because the job system doesn’t allow you to schedule a job that has write access to a NativeContainer instance at the same time as another job that’s writing to it.

However, If a job doesn’t need to write to a NativeContainer instance, you can mark the NativeContainer with the [ReadOnly] attribute, like so:

[ReadOnly]
public NativeArray<int> input;

In the above example, you can execute the job at the same time as other jobs that also have read-only access to the first NativeArray.

Memory allocators

When you create a NativeContainer instance, you must specify the memory allocator type to use with it. The allocation type you use depends on how long you want to keep the native container available for. This way you can tailor the allocation to get the best performance possible in each situation.

For example:

NativeArray<float> result = new NativeArray<float>(1, Allocator.TempJob);

Note: The number 1 in the example above indicates the size of the NativeArray. In this case, it has only one array element because it only stores one piece of data in its result.

Valid allocator types are those from the Allocator enumeration. For more information on these allocators and their features, refer to Introduction to allocators.

NativeContainer safety system

The safety system is built into all NativeContainer instances. It tracks what reads or writes to any NativeContainer instance, and uses that information to enforce certain rules on the use of NativeContainers that makes them behave in a deterministic way across multiple jobs and threads.

For example, if two independent scheduled jobs write to the same NativeArray, this is unsafe because you can’t predict which job executes first. This means that you won’t know which of the jobs will overwrite data from the other. The safety system throws an exception with a clear error message that explains why and how to solve the problem, when you schedule the second job.

If you want to schedule two jobs that write to the same NativeContainer instance, you can schedule the jobs with a dependency. The first job writes to the NativeContainer, and once it has finished executing, the next job safely reads and writes to that same NativeContainer. Introducing the dependency guarantees that the jobs always execute in a consistent order and that the resulting data in the NativeContainer is deterministic.

The safety system allows multiple jobs to read from the same data in parallel.

These read and write restrictions also apply when accessing data from the main thread. For example, if you try to read the contents of a NativeContainer before the job that writes to it has completed, the safety system throws an error. Likewise, if you try to write to a NativeContainer while there are still pending jobs that read or write to it, then the safety system also throws an error.

Also, because NativeContainers don’t implement ref return, you can’t directly change the contents of a NativeContainer. For example, nativeArray[0]++; is the same as writing var temp = nativeArray[0]; temp++; which doesn’t update the value in nativeArray.

Instead, you must copy the data from the index into a local temporary copy, modify that copy, and save it back. For example:

MyStruct temp = myNativeArray[i];
temp.memberVariable = 0;
myNativeArray[i] = temp;

Additional resources

Thread safe types
Implement a custom native container