Simplify synchronization

- Use `synchronized` on the queue sets in favor of explicit locks.
 - Updates and additions work the same now
 - Move updates processing to separate function
This commit is contained in:
Jozufozu 2021-08-03 02:06:41 -07:00 committed by GitHub
parent 9ae823ef92
commit 7eb0284db9
Failed to generate hash of commit

View file

@ -1,12 +1,16 @@
package com.jozufozu.flywheel.backend.instancing; package com.jozufozu.flywheel.backend.instancing;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet;
import java.util.Map; import java.util.Map;
import java.util.Objects; import java.util.Objects;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.locks.ReadWriteLock; import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock; import java.util.concurrent.locks.ReentrantReadWriteLock;
import java.util.function.Consumer;
import javax.annotation.Nullable; import javax.annotation.Nullable;
@ -14,6 +18,7 @@ import com.jozufozu.flywheel.backend.Backend;
import com.jozufozu.flywheel.backend.material.MaterialManager; import com.jozufozu.flywheel.backend.material.MaterialManager;
import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap;
import it.unimi.dsi.fastutil.objects.ObjectArraySet;
import net.minecraft.client.renderer.ActiveRenderInfo; import net.minecraft.client.renderer.ActiveRenderInfo;
import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.vector.Vector3f; import net.minecraft.util.math.vector.Vector3f;
@ -22,12 +27,8 @@ public abstract class InstanceManager<T> implements MaterialManager.OriginShiftL
public final MaterialManager<?> materialManager; public final MaterialManager<?> materialManager;
//Thread locks to ensure concurrent access exceptions don't occur private final Set<T> queuedAdditions;
private final ReadWriteLock queuedUpdatesLock = new ReentrantReadWriteLock(); private final Set<T> queuedUpdates;
private final ReadWriteLock queuedAdditionsLock = new ReentrantReadWriteLock();
private final ArrayList<T> queuedAdditions;
private final ConcurrentHashMap.KeySetView<T, Boolean> queuedUpdates;
protected final Map<T, IInstance> instances; protected final Map<T, IInstance> instances;
protected final Object2ObjectOpenHashMap<T, ITickableInstance> tickableInstances; protected final Object2ObjectOpenHashMap<T, ITickableInstance> tickableInstances;
@ -38,8 +39,8 @@ public abstract class InstanceManager<T> implements MaterialManager.OriginShiftL
public InstanceManager(MaterialManager<?> materialManager) { public InstanceManager(MaterialManager<?> materialManager) {
this.materialManager = materialManager; this.materialManager = materialManager;
this.queuedUpdates = ConcurrentHashMap.newKeySet(64); this.queuedUpdates = new HashSet<>(64);
this.queuedAdditions = new ArrayList<>(64); this.queuedAdditions = new HashSet<>(64);
this.instances = new HashMap<>(); this.instances = new HashMap<>();
this.dynamicInstances = new Object2ObjectOpenHashMap<>(); this.dynamicInstances = new Object2ObjectOpenHashMap<>();
@ -56,6 +57,7 @@ public abstract class InstanceManager<T> implements MaterialManager.OriginShiftL
public void tick(double cameraX, double cameraY, double cameraZ) { public void tick(double cameraX, double cameraY, double cameraZ) {
tick++; tick++;
processQueuedUpdates();
// integer camera pos // integer camera pos
int cX = (int) cameraX; int cX = (int) cameraX;
@ -79,21 +81,6 @@ public abstract class InstanceManager<T> implements MaterialManager.OriginShiftL
if ((tick % getUpdateDivisor(dX, dY, dZ)) == 0) instance.tick(); if ((tick % getUpdateDivisor(dX, dY, dZ)) == 0) instance.tick();
}); });
} }
//suggested replacement ?
//Unable to confirm if the call to update(te) causes updates to the que.
//queuedUpdatesLock.writeLock().lock();
//*
queuedUpdates.forEach(te -> {
queuedUpdates.remove(te);
update(te);
});//*/
//queuedUpdates.forEach(this::update);
//queuedUpdates.clear();
//queuedUpdatesLock.writeLock().unlock();
} }
public void beginFrame(ActiveRenderInfo info) { public void beginFrame(ActiveRenderInfo info) {
@ -134,9 +121,9 @@ public abstract class InstanceManager<T> implements MaterialManager.OriginShiftL
if (!Backend.getInstance() if (!Backend.getInstance()
.canUseInstancing()) return; .canUseInstancing()) return;
queuedAdditionsLock.writeLock().lock(); synchronized (queuedAdditions) {
queuedAdditions.add(obj); queuedAdditions.add(obj);
queuedAdditionsLock.writeLock().unlock(); }
} }
public void update(T obj) { public void update(T obj) {
@ -162,9 +149,9 @@ public abstract class InstanceManager<T> implements MaterialManager.OriginShiftL
public synchronized void queueUpdate(T obj) { public synchronized void queueUpdate(T obj) {
if (!Backend.getInstance() if (!Backend.getInstance()
.canUseInstancing()) return; .canUseInstancing()) return;
queuedUpdatesLock.writeLock().lock(); synchronized (queuedUpdates) {
queuedUpdates.add(obj); queuedUpdates.add(obj);
queuedUpdatesLock.writeLock().unlock(); }
} }
public void onLightUpdate(T obj) { public void onLightUpdate(T obj) {
@ -195,7 +182,6 @@ public abstract class InstanceManager<T> implements MaterialManager.OriginShiftL
tickableInstances.clear(); tickableInstances.clear();
} }
@SuppressWarnings("unchecked")
@Nullable @Nullable
protected <I extends T> IInstance getInstance(I obj, boolean create) { protected <I extends T> IInstance getInstance(I obj, boolean create) {
if (!Backend.getInstance() if (!Backend.getInstance()
@ -212,16 +198,32 @@ public abstract class InstanceManager<T> implements MaterialManager.OriginShiftL
} }
} }
protected synchronized void processQueuedAdditions() { protected void processQueuedAdditions() {
queuedAdditionsLock.writeLock().lock(); ArrayList<T> queued;
ArrayList<T> queued = new ArrayList<>(queuedAdditions);
synchronized (queuedAdditions) {
queued = new ArrayList<>(queuedAdditions);
queuedAdditions.clear(); queuedAdditions.clear();
queuedAdditionsLock.writeLock().unlock(); }
if (queued.size() > 0) { if (queued.size() > 0) {
queued.forEach(this::addInternal); queued.forEach(this::addInternal);
} }
} }
protected void processQueuedUpdates() {
ArrayList<T> queued;
synchronized (queuedUpdates) {
queued = new ArrayList<>(queuedUpdates);
queuedUpdates.clear();
}
if (queued.size() > 0) {
queued.forEach(this::update);
}
}
protected boolean shouldFrameUpdate(BlockPos worldPos, float lookX, float lookY, float lookZ, int cX, int cY, int cZ) { protected boolean shouldFrameUpdate(BlockPos worldPos, float lookX, float lookY, float lookZ, int cX, int cY, int cZ) {
int dX = worldPos.getX() - cX; int dX = worldPos.getX() - cX;
int dY = worldPos.getY() - cY; int dY = worldPos.getY() - cY;