Renderer/src/main/java/electrosphere/engine/threads/ThreadManager.java
austin d8b89aac7d
All checks were successful
studiorailgun/Renderer/pipeline/head This commit looks good
fix framebuffer caching bug
2024-09-09 12:42:29 -04:00

154 lines
4.4 KiB
Java

package electrosphere.engine.threads;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;
import electrosphere.engine.Globals;
import electrosphere.engine.loadingthreads.LoadingThread;
import electrosphere.engine.threads.LabeledThread.ThreadLabel;
import electrosphere.util.CodeUtils;
/**
* Manages all running threads
*/
public class ThreadManager {
//Threadsafes the manager
Semaphore threadLock = new Semaphore(1);
//All threads that are actively running
private List<LabeledThread> activeThreads = new LinkedList<LabeledThread>();
//All loading threads that are actively running
private List<LoadingThread> loadingThreads = new LinkedList<LoadingThread>();
//Used by main thread to alert other threads whether they should keep running or not
private boolean shouldKeepRunning = true;
/**
* Updates what threads are being tracked
*/
public void update(){
threadLock.acquireUninterruptibly();
//
//remove loading threads
List<Thread> threadsToRemove = new LinkedList<Thread>();
for(LoadingThread thread : loadingThreads){
if(thread.isDone()){
threadsToRemove.add(thread);
}
}
for(Thread thread : threadsToRemove){
loadingThreads.remove(thread);
}
threadLock.release();
}
/**
* Starts a new thread with tracking
* @param thread The thread to start
*/
public void start(ThreadLabel label, Thread thread){
threadLock.acquireUninterruptibly();
activeThreads.add(new LabeledThread(label, thread));
thread.start();
threadLock.release();
}
/**
* Starts a new loading thread with tracking
* @param thread The loading thread to start
*/
public void start(LoadingThread thread){
threadLock.acquireUninterruptibly();
activeThreads.add(new LabeledThread(ThreadLabel.LOADING, thread));
loadingThreads.add(thread);
thread.start();
threadLock.release();
}
/**
* Checks if any loading threads are active
* @return true if there is an active loading thread, false otherwise
*/
public boolean isLoading(){
return loadingThreads.size() > 0;
}
/**
* Gets the list of loading threads
* @return The list of loading threads
*/
public List<LoadingThread> getLoadingThreads(){
return Collections.unmodifiableList(loadingThreads);
}
/**
* Tries to close all threads
*/
public void close(){
this.shouldKeepRunning = false;
threadLock.acquireUninterruptibly();
//for some reason, server must be explicitly closed
if(Globals.server != null){
Globals.server.close();
}
//
//interrupt all threads
for(int i = 0; i < 3; i++){
for(LabeledThread thread : activeThreads){
thread.getThread().interrupt();
try {
thread.getThread().join(10);
if(thread.getThread().isAlive()){
String errorMessage = "Failed to interrupt thread! " + thread.getLabel();
System.err.println(errorMessage);
throw new IllegalStateException();
}
} catch (InterruptedException e) {
CodeUtils.todo(e, "Think about how to handle this");
}
}
try {
TimeUnit.MILLISECONDS.sleep(3);
} catch (InterruptedException e) {
CodeUtils.todo(e, "Handle failing to sleep while interrupting all other threads");
}
}
threadLock.release();
}
/**
* Checks if the thread should keep running or not
* @return true if should keep running, false otherwise
*/
public boolean shouldKeepRunning(){
return this.shouldKeepRunning;
}
/**
* Interrupts all thread under a label
* @param label The label
*/
public void interruptLabel(ThreadLabel label){
threadLock.acquireUninterruptibly();
//
//interrupt threads
for(LabeledThread thread : activeThreads){
if(thread.getLabel() == label){
thread.getThread().interrupt();
}
}
threadLock.release();
}
}