Reputation: 3
I am trying to create a platform for testing mutual exclusion algorithms using Swing. My intent is to display servers and messages being sent between them in the GUI. I also want to display a critical section which shows which servers are currently accessing it. I am using a threadpool that executes SwingWorker threads to deploy the servers which load a user selected mutex algorithm.
The program runs as expected until I try to implement the message displays. To display an arrow for each message I've extended SwingWorker, UIArrowThread, to add a JLabel that draws an arrow from the source server to the target. This thread waits for 1 second before removing the JLabel. This seems to be working fine when I explicitly create one or more of these messages(I've also created a test platform where I can create specific messages).
The problem comes when I try to integrate this SwingWorker thread into the program. When the algorithm is started, each server attempts to access the critical section and sends its requests to each of the other servers. This should invoke UIArrowThread but it appears that only some servers actually create the thread.
public void sendMsg(int destId, Object ... objects) {
comm.sendMsg(destId, objects);
try{
UIArrowThread a = new UIArrowThread(AlgorithmSimulatorUI.jlp,
objects[0].toString(),
comm.getMyId(),
destId);
AlgorithmSimulatorUI.threadPool.execute(a);
} catch (Exception exc){
System.err.println(exc);
}
}
Some of the servers just seem to stop executing just before instantiating UIArrowThread and ends up creating a deadlock. Any servers that do make it passed that point work normal and the GUI displays as it should be. I have testing with logging just before UIArrowThread is called and in its constructor. The threads that look like they stop executing never make the log call in the constructor. I'm pretty stumped on why this would be happening.
public class UIArrowThread extends SwingWorker<Integer, String>{
JLayeredPane jlp;
String type;
int source;
int target;
Point start;
Point end;
Point[] points;
int quadrant;
public UIArrowThread(JLayeredPane jlp, String msg_type, int source,
int target){
this.jlp = jlp;
this.type = msg_type;
this.source = source;
this.target = target;
this.points = getPoints();
this.start = points[0];
this.end = points[1];
}
@Override
protected Integer doInBackground(){
Point lblPoint = getLabelCoordinates(points);
ArrowLabel arrow = new ArrowLabel(type, 1, 2, jlp, points, quadrant);
if (quadrant < 5){
arrow.setBounds(lblPoint.x, lblPoint.y, abs(start.x - end.x),
abs(start.y - end.y));
} else if (quadrant < 7){
arrow.setBounds(lblPoint.x, lblPoint.y, 100, abs(start.y - end.y));
} else {
arrow.setBounds(lblPoint.x, lblPoint.y, abs(start.x - end.x), 100);
}
jlp.add(arrow);
String openHTML = "<html><font color='red',size=12>";
String closeHTML = "</font></html>";
arrow.setText(openHTML + type + closeHTML);
arrow.setHorizontalTextPosition(JLabel.CENTER);
arrow.setVerticalTextPosition(JLabel.CENTER);
jlp.repaint();
try{
Thread.sleep(arrow.lifespan);
} catch (Exception exc){
System.err.println(exc);
} finally {
jlp.remove(arrow);
}
jlp.repaint();
return 1;
}
I've added what I feel would be the relevant part of code for this problem. As mentioned above, if I remove the UIArrowThread, the program will run correctly.
I tried a few more approaches that still produce the same results including doing the work in process() instead of doInBackground(), and having the ArrowLabel remove itself from the GUI instead of UIArrowThread doing the removal.
Update:
I was able to get the UI working as intended but still not really sure what the original issue is. The program has a messaging queue that displays the messages from servers in a textPane so I figured I'd update the UI with the arrow labels here. It was not neccessary to alter any of the existing code for ArrowLabel or UIArrowThread.
Upvotes: 0
Views: 101
Reputation: 205785
Your fragment suggests that you are updating a Swing component, ArrowLabel
, in the doInBackground()
method of a SwingWorker
. This violates the Swing single-thread rule. Instead, query the servers in the background, publish()
interim results, and process()
them on the EDT, as shown in the examples examined here. The exact formulation of "the type used for carrying out intermediate results by this SwingWorker's publish and process methods" will depend on your use case. As a concrete example, this TableSwingWorker
extends SwingWorker<MyTableModel, RowData>
, publishing instances of RowData
used to update a TableModel
Upvotes: 5