Job runs, but job data is empty?

Hi,

strange problem here, this is the job:

public struct MoveExistingVegetation : IJobForEach<Tree>
    {
        public NativeArray<float3> NewTreePositions;
        public float2 NewMiddlePoint;
        public int Counter;

        public void Execute(ref Tree tree)
        {

            if (!Utils.IsPositionInsideCurrentMiddlePoint(tree.position, NewMiddlePoint))
            {
                if (Counter < NewTreePositions.Length)
                {

                    tree.position = NewTreePositions[Counter];

                    //BREAKPOINT
                    Counter++;
                }

            }
        }
    }

And this is the code which is trying to extract the data:

            //BREAKPOINT
            var job = new MoveExistingVegetation()
            {
                NewMiddlePoint = newId,
                NewTreePositions = blablabla
            };

            var handle = job.Schedule(this);

            handle.Complete();
            //BREAKPOINT
            PrefabManager.Log("We moved Trees: " + job.Counter);

What i want: Iterate over each Tree, sometimes do stuff, then return the count of all trees where i did something.

The Problem is that Count is ALWAYS! 0.

Even if i put breakpoints on the lines i marked with //BREAKPOINT, i see that everything is run in order (eg the job is constructed, then inside we count up 2 times, then i get outside the job, but here the values are lost.

Job is a struct and struct is passed by value.
You should use NativeArray<int> Counter instead of the int, with length equal to cores count and with job thread index or run in the single thread.

public struct MoveExistingVegetation : IJobForEach<Tree>
    {
        public NativeArray<float3> NewTreePositions;
        public float2 NewMiddlePoint;
        public NativeArray<int> Counter;

        public void Execute(ref Tree tree)
        {
            if (!Utils.IsPositionInsideCurrentMiddlePoint(tree.position, NewMiddlePoint))
            {
                if (Counter[0] < NewTreePositions.Length)
                {

                    tree.position = NewTreePositions[Counter[0]];

                    //BREAKPOINT
                    Counter[0] = Counter[0] + 1;
                }

            }
        }
    }

            var counter = new NativeArray<int>(1, Allocator.TempJob);
          
            var job = new MoveExistingVegetation()
            {
                NewMiddlePoint = newId,
                NewTreePositions = blablabla,
                Counter = counter,
            };

            var handle = job.ScheduleSingle(this);

            handle.Complete();
            //BREAKPOINT
            PrefabManager.Log("We moved Trees: " + counter[0]);
            counter.Dispose();

There is a racecondition happening: I have 750 Objects, but when iterating over each one, i count most of the times only 740/744.

Is there a way to force the job on only a single thread or is there a different way to do this @ilih Maybe ForEachWithEntitie? What is the index used for?

This way you safely write to counter and then get counter sum.
But I don’t have advice on how to do multithread read from NewTreePositions without getting same value.

            var counter = new NativeArray<int>(JobsUtility.MaxJobThreadCount, Allocator.TempJob);

            var job = new MoveExistingVegetation()
            {
                NewMiddlePoint = newId,
                NewTreePositions = blablabla,
                Counter = counter,
            };
            var handle = job.Schedule(this);

            handle.Complete();
            //BREAKPOINT
            PrefabManager.Log("We moved Trees: " + sum(counter));
            counter.Dispose();

        struct MoveExistingVegetation : IJobForEachWithEntity<Tree>
        {
            public NativeArray<float3> NewTreePositions;
            public float2 NewMiddlePoint;

            [NativeDisableParallelForRestriction]
            public NativeArray<Unity.Mathematics.Random> Counter;

            [Unity.Collections.LowLevel.Unsafe.NativeSetThreadIndex]
            int threadId;

            public void Execute(ref Tree tree)
            {
                if (!Utils.IsPositionInsideCurrentMiddlePoint(tree.position, NewMiddlePoint))
                {
                    if (Counter[threadId] < NewTreePositions.Length)
                    {
                        tree.position = ???;

                        Counter[jobIndex] = Counter[jobIndex] + 1;
                    }
                }
            }
        }

Use IJob. Is single threaded. Then you can use burst.

IJobForEach has ScheduleSingle(), forces a single thread.

If you use IJobForEachWithEntity, you can use a concurrent NatIveQueue if that works. Just feed the Queue the job index and you can parallelize it.