Skip to content

Commit

Permalink
revised after @lightvector's review
Browse files Browse the repository at this point in the history
  • Loading branch information
Hiraoka committed Sep 24, 2020
1 parent 7d3a4d3 commit 0a047eb
Showing 1 changed file with 46 additions and 24 deletions.
70 changes: 46 additions & 24 deletions src/main/java/featurecat/lizzie/analysis/Leelaz.java
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,6 @@ public class Leelaz {
private BufferedOutputStream outputStream;

private WriterThread writerThread;
private ArrayDeque<String> writerQueue;

private boolean printCommunication;
public boolean gtpConsole;
Expand Down Expand Up @@ -130,8 +129,6 @@ public Leelaz(String engineCommand) throws JSONException {
commands = splitCommand(engineCommand);
// Initialize current engine number and start engine
currentEngineN = 0;

startWriterThread();
}

public void startEngine() throws IOException {
Expand Down Expand Up @@ -183,6 +180,7 @@ public void startEngine() throws IOException {
process = processBuilder.start();

initializeStreams();
startWriterThread();

// Send a name request to check if the engine is KataGo
// Response handled in parseLine
Expand Down Expand Up @@ -235,6 +233,7 @@ public void normalQuit() {
executor.shutdownNow();
Thread.currentThread().interrupt();
}
stopWriterThread();
started = false;
isLoaded = false;
Lizzie.engineManager.updateEngineIcon();
Expand Down Expand Up @@ -971,52 +970,75 @@ public void setWeightName() {

// Writer thread for avoiding deadlock (#752)
class WriterThread extends Thread {
public ArrayDeque<String> writerQueue = new ArrayDeque<>();
private ArrayDeque<String> privateQueue = new ArrayDeque<>();
public boolean shouldStopNow = false;

public void run() {
// ref.
// https://docs.oracle.com/en/java/javase/15/docs/api/java.base/java/lang/doc-files/threadPrimitiveDeprecation.html
while (true) {
// move requests to privateQueue so that writerQueue is not blocked
// even when outputStream is stalled.
synchronized (writerQueue) {
synchronized (this) {
while (writerQueue.isEmpty() && !shouldStopNow) {
try {
wait();
} catch (InterruptedException e) {
}
}
if (shouldStopNow) return;
// Note that outputStream can be stalled by massive GTP commands (#752).
// We move requests from writerQueue to privateQueue
// so that we can release the lock BEFORE using outputStream.
// Then other threads can send new requests to writerQueue
// even when writer thread is blocked in writeToStream().
while (!writerQueue.isEmpty()) {
String command = writerQueue.removeFirst();
privateQueue.addLast(command);
}
}
if (outputStream != null) {
try {
while (!privateQueue.isEmpty()) {
String command = privateQueue.removeFirst();
outputStream.write(command.getBytes());
}
outputStream.flush();
} catch (IOException e) {
e.printStackTrace();
}
}
writeToStream();
}
}

private void writeToStream() {
if (outputStream != null) {
try {
synchronized (this) {
wait();
while (!privateQueue.isEmpty()) {
String command = privateQueue.removeFirst();
outputStream.write(command.getBytes());
}
} catch (InterruptedException e) {
outputStream.flush();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}

public void startWriterThread() {
writerQueue = new ArrayDeque<>();
writerThread = this.new WriterThread();
writerThread.start();
}

public void sendToWriterThread(String string) {
synchronized (writerQueue) {
writerQueue.addLast(string);
public void stopWriterThread() {
if (writerThread == null) return;
synchronized (writerThread) {
writerThread.shouldStopNow = true;
writerThread.notify();
}
// Wait for writer thread to notice the shouldStopNow and actually finish terminating
try {
writerThread.join();
} catch (InterruptedException e) {
}
// Reset it to null now that it is dead. All cleaned up
writerThread = null;
}

public void sendToWriterThread(String command) {
if (writerThread == null) return;
synchronized (writerThread) {
writerThread.writerQueue.addLast(command);
writerThread.notify();
}
}
Expand Down

0 comments on commit 0a047eb

Please sign in to comment.