Problem: I need 3 threads. Thread1 reads an int-value and starts an action (that involves a UI) if this value changes. Thread2 is the UI. Thread3 is the action that should be performed when Thread1 notices that the int changed. Now, when I start thread2 and then do
display.async(new Thread1())
it won't show the UI since the open()-method is called later. When I do open() first and then display.async() it'll throw an SWTException immediately:
Exception in thread "Thread-0" org.eclipse.swt.SWTException: Failed to execute runnable (org.eclipse.swt.SWTException: Invalid thread access)
at org.eclipse.swt.SWT.error(Unknown Source)
at org.eclipse.swt.SWT.error(Unknown Source)
at org.eclipse.swt.widgets.Synchronizer.runAsyncMessages(Unknown Source)
at org.eclipse.swt.widgets.Display.runAsyncMessages(Unknown Source)
at org.eclipse.swt.widgets.Display.readAndDispatch(Unknown Source)
at sokobangui.SokobanGUIManager.run(SokobanGUIManager.java:57)
at java.lang.Thread.run(Unknown Source)
Caused by: org.eclipse.swt.SWTException: Invalid thread access
at org.eclipse.swt.SWT.error(Unknown Source)
at org.eclipse.swt.SWT.error(Unknown Source)
at org.eclipse.swt.SWT.error(Unknown Source)
at org.eclipse.swt.widgets.Display.checkDisplay(Unknown Source)
at org.eclipse.swt.widgets.Display.create(Unknown Source)
at org.eclipse.swt.graphics.Device.(Unknown Source)
at org.eclipse.swt.widgets.Display.(Unknown Source)
at org.eclipse.swt.widgets.Display.(Unknown Source)
at sokobangui.SokobanGUIManager.run(SokobanGUIManager.java:35)
at java.lang.Thread.run(Unknown Source)
at org.eclipse.swt.widgets.RunnableLock.run(Unknown Source)
... 5 more
When I start thread1 and thread2 seperately without trying to sync them it works fine until I try to initialize thread3 by using thread2. Then I get this one:
Exception in thread "Thread-1" org.eclipse.swt.SWTException: Invalid thread access
at org.eclipse.swt.SWT.error(Unknown Source)
at org.eclipse.swt.SWT.error(Unknown Source)
at org.eclipse.swt.SWT.error(Unknown Source)
at org.eclipse.swt.widgets.Widget.error(Unknown Source)
at org.eclipse.swt.widgets.Widget.checkWidget(Unknown Source)
at org.eclipse.swt.widgets.Control.getShell(Unknown Source)
at sokobangui.GUICoordinator.switchToRoboControl(GUICoordinator.java:120)
at sokobangui.GUIListener.run(GUIListener.java:15)
at java.lang.Thread.run(Unknown Source)
So if I was asked what happened here I'd say there's some problem with sychronizing the threads since as far as I know the display-thread needs to 'know' which threads will modify the surface. However I have no idea how to solve that problem...
Here're some code snippets: (thread1 = GUIListener; thread2 = SokobanGUIManager; thread3 = SwitchToRoboControl)
public class StartSokobanSolver {
public static void main(String[] args) {
GUIStatus.status = GUIStatus.MAIN;
Thread manager = new Thread(new SokobanGUIManager());
manager.start();
//Thread listener = new Thread(new GUIListener());
//listener.start();
}
}
public class SokobanGUIManager implements Runnable {
public void run() {
this.display = new Display();
this.display.asyncExec(new Thread(new GUIListener()));
this.shell = new Shell(this.display);
goToMainMenu();
this.shell.open();
while (!this.shell.isDisposed()) {
if (!display.readAndDispatch()) {
display.sleep();
}
}
GUIStatus.status = GUIStatus.END;
}
}
public class GUIListener implements Runnable {
private static GUICoordinator connector;
@Override
public void run() {
while (!Thread.currentThread().isInterrupted()) {
//try{
while(GUIStatus.status != GUIStatus.END) {
System.out.println("GUI-Status: " + GUIStatus.status);
if(GUIStatus.status == GUIStatus.INGAME_ROBOT) {
System.out.println("InGameRobot Start");
connector.switchToRoboControl();
System.out.println("InGameRobot End");
GUIStatus.status = GUIStatus.INGAME_SOLVED;
connector.isSolved();
} else {
System.out.println("Else");
try{ Thread.sleep(5000); } catch(Exception e) {}
}
if(GUIStatus.status == GUIStatus.END) {
Thread.currentThread().interrupt();
}
}
/*} catch(Exception e) {
System.out.println("Ende des Threads : " + e.toString());
Thread.currentThread().interrupt();
Not in the code atm to get the full exception message!
}*/
}
}
protected static void setCoordinator(GUICoordinator c) {
connector = c;
}
}
public class GUICoordinator {
...
protected void switchToRoboControl() {
if(this.roboControl != null) {
Solution solution = new Solution("1u:1l:1d");
Thread roco = new Thread(new SwitchToRoboControl(this.map, this, this.mapArea.getShell(), solution));
Display.getDefault().asyncExec(roco);
roco.start();
System.out.println("Thread started");
} else {
System.out.println("Epic fail");
}
}
}
public class SwitchToRoboControl implements Runnable {
...
public SwitchToRoboControl(Map map, GUICoordinator gui, Shell shell, Solution solution) {
this.map = map;
this.gui = gui;
this.shell = shell;
this.solution = solution;
}
@Override
public void run() {
...action to be performed
}
}