Dear list,
I have written a set of PlugIns for our image analysis which make use of Threading using the RunnableJob method. The scripts work as intended when launched from the ImageJ or Fiji plugings menu and from the plugins editor. When I try to run the plugin from a button in a Frame, the program hangs. By excising bits of code, I've narrowed the problem down to several commands, including: IJ.run("Set Measurements...") imp.close(); These are commands I have used before with no problems and I cannot see why the program only hangs when started from a button, but not from the main menu. The following code reproduces the arrangement of the code I have, and gives the same fault. When the IJ.run("set Measurements...") is commented out (line 53, ThreadTest Class), the program runs fine; when it is included, the program crashes. Any suggestions as to what is happening or why would be greatfully received. Andrew Bell Research Associate University of Leicester //Frame class: import ij.*; import ij.process.*; import ij.gui.*; import java.awt.*; import ij.plugin.frame.*; import java.awt.event.*; public class ButtonFrame extends PlugInFrame implements ActionListener { public ButtonFrame() { super("ButtonFrame"); Button ta = new Button("Start"); ta.addActionListener(this); add(ta);pack();show(); } public void actionPerformed(ActionEvent e){ IJ.log("Button Clicked"); ThreadTest tt = new ThreadTest(); tt.run(""); } } //Thread class: import ij.*; import ij.process.*; import ij.gui.*; import java.awt.*; import ij.plugin.*; public class ThreadTest implements PlugIn { public RunnableJob runnableJob = new RunnableJob(); public String[] str_list = {"Apples","Stairs"}; public void run(String arg){ for(int i=0; i<str_list.length;i++){ try{ Thread t = new Thread(runnableJob, str_list[i]); t.start(); t.join(); }catch (InterruptedException ex) { IJ.showMessage("Error",""+ex); } } IJ.log("Complete"); }// end of ThreadTest run public class RunnableJob implements Runnable { public String name; public void run() { Thread thread = Thread.currentThread(); name = thread.getName(); try { TestFunction tf = new TestFunction(); tf.run(name); } catch (Exception e) { IJ.showMessage("Error",""+e); } } } //end of RunnableJob public class TestFunction { public void run(String arg){ try{ int x = (int)(Math.random() * 1000); Thread.sleep(x); IJ.log(arg+" "+x+" ms delay"); //IJ.run("Set Measurements...", "area perimeter fit feret's integrated display redirect=None decimal=3"); } catch(Exception e){ IJ.log(""+e); } } }// end of TestFunction } //class end |
Hi Andrew,
On Tue, 18 Feb 2014, AJBell wrote: > I have written a set of PlugIns for our image analysis which make use of > Threading using the RunnableJob method. The scripts work as intended > when launched from the ImageJ or Fiji plugings menu and from the plugins > editor. When I try to run the plugin from a button in a Frame, the > program hangs. I am glad that the program does not crash Fiji -- as suggested by the mail's subject. Please be careful when describing software behavior (a crash means that the program quits unexpectedly without giving the user a chance to save her data, something quite different from a hang that does not allow the user to interact with the program anymore). > Thread t = new Thread(runnableJob, str_list[i]); > t.start(); > t.join(); The "join()" is the problem. Remember: your button press is detected and handled on the event dispatch thread (EDT). It calls actionPerformed() eventually, still on the EDT. Then you start a thread -- this thread will run parallel to the EDT. But now "join()" is called -- waiting for the other thread to return. The "join()" call is run *on the EDT*, blocking event dispatching until further notice. Now, that usually only makes the GUI unresponsive until the started thread is done. Except if that other thread tries to send an event itself -- which imp.close() does: it needs to close the window, and that is done via sending a WindowClosingEvent and then WindowCloseEvent. Those messages are sent, and then the other thread *waits* until the events are handled. Those events will need to be handled on the EDT, though, and that thread is blocked. Basically, the EDT is blocked waiting for the other thread while the other thread says: no, you first. It's like Mid-West traffic: trying to be polite and let the other go first, everybody just sits and waits. A better way would be to design the program with less need to control: let it spawn the threads and return. If something needs to be done in response to those threads returning, it should be done at the end of those threads. In general, it is a very good idea to spend as little time as possible blocking the EDT. A good practice is to implement the real action as a Runnable that the event handler will wrap in a Thread and start() it ("fire 'n forget" style). Ciao, Johannes -- ImageJ mailing list: http://imagej.nih.gov/ij/list.html |
Free forum by Nabble | Edit this page |