Link to home
Start Free TrialLog in
Avatar of jkteater
jkteaterFlag for United States of America

asked on

Stopping Thread B when Thread A completes with a Condition

I have a long running operation in my AplotPDFDialog Dialog.  So I want to show the user a Progress Bar to let them know the operation is in progress.  Mainly because they can not continue to work until the operation completes.

Here are the 3 classes:
The base dialog class  =   AplotPDFDialog
  SubClass -  The operation class  =      MyOperationListener
  SubClass  - The Progress Bar class =  ProgressBarThread

This is how I have it working today.

The  startSavePdfOperation method in the Dialog class is called by a button click.


private void startSavePdfOperation() {
Display.getDefault().asyncExec(new Runnable() {
         public void run() {
            startProgressBar();
         }
      });
      saveOp = new AplotSaveOperation(appReg.getString("aplot.message.SAVETOPDF"), "PDF", session);
      saveOp.addOperationListener(new MyOperationListener(this) { 
        
         public void endOperationImpl() {
            java.io.File zipFile = null;
            try {               
               AplotSaveResultsParser.SaveResult saveResults = saveOp.getSaveResults();
               if (saveResults != null) {
                  if (!saveResults.hasZipFile) {
                     StringBuffer sb = new StringBuffer();
                     sb.append(saveResults.error);
                     sb.append(":\n");
                     for (int i = 0; i < saveResults.datasetSaveResults.size(); ++i) {
                        AplotSaveResultsParser.DatasetSaveResult dsr = (AplotSaveResultsParser.DatasetSaveResult) saveResults.datasetSaveResults.get(i);
                        sb.append(dsr.fileInZipOrError);
                        sb.append("\n");
                     }
                     throw new RuntimeException(sb.toString());
                  }
                  zipFile = saveOp.getZipFile(saveResults);
                 //addSaveResults(saveResults);
                  performRenameOperation(zipFile, saveResults);
               } // end if
            } // end try
            catch (Exception e) {
               e.printStackTrace();
            }
            finally {
               saveOp.removeOperationListener(this);
               saveOp = null;
               if (zipFile != null) {
                  try { zipFile.delete(); } catch (Exception e) {}
               }
               Display.getDefault().asyncExec(new Runnable() {
                  public void run() {
                    baseDialog.clearArrays();
                 }
               });
            }
         }
      });
      session.queueOperation(saveOp);
   } // end startSavePdfOperation()

Open in new window


At the very start of the method I am Starting the Progress Bar in a separate thread.

Display.getDefault().asyncExec(new Runnable() {
         public void run() {
            startProgressBar();
         }
      });

Open in new window


Method for ProgressBar

 public void startProgressBar() {
      try {
         new ProgressMonitorDialog(getShell()).run(true, false,
            new ProgressBarThread());
      } 
      catch (InvocationTargetException e) {
         MessageDialog.openError(getShell(), "Error", e.getMessage());
      } 
      catch (InterruptedException e) {
         MessageDialog.openInformation(getShell(), "Cancelled", e.getMessage());
      }
   }

Open in new window


ProgressBar Class

class ProgressBarThread implements IRunnableWithProgress  {
      private static final int TOTAL_TIME = 10000;
      private static final int INCREMENT = 1000;
      
      public ProgressBarThread() {
         
      }
      
      public void run(IProgressMonitor monitor) throws InvocationTargetException,InterruptedException {
         monitor.beginTask("Creating PDF File(s)", IProgressMonitor.UNKNOWN);
         for (int total = 0; total < TOTAL_TIME ; total += INCREMENT) {
            Thread.sleep(INCREMENT);
            monitor.worked(INCREMENT);
            if (total == TOTAL_TIME / 2) monitor.subTask("Please be patient... Operation should finish soon.");
        }
        monitor.done();
        
      }

Open in new window



Then the listener is added to the long running operation. See Method Above

saveOp.addOperationListener(new MyOperationListener(this)

Open in new window


MyOperationListener Class

public abstract class MyOperationListener implements InterfaceAIFOperationListener {
      AplotCreatePDFDialog w = null;
           
      public MyOperationListener(AplotCreatePDFDialog win) {
         w = win;
      } 
          
      public void startOperation(String startMessage) {
         Display.getDefault().asyncExec(new Runnable() {
            public void run() {
               //w.startProgressBar();
               w.getShell().setCursor(new Cursor(Display.getCurrent(), SWT.CURSOR_WAIT));
               w.recursiveSetEnabled(getShell(), getShell().getEnabled());
               w.getShell().setEnabled(!getShell().getEnabled());
            }
         });
      } 

      public void endOperation() {
         try {
            endOperationImpl();
         }
         finally {
            Display.getDefault().asyncExec(new Runnable() {
               public void run() {
                  w.getShell().setCursor(new Cursor(Display.getCurrent(), SWT.CURSOR_ARROW));
                  w.recursiveSetEnabled(getShell(), true);
                  w.getShell().setEnabled(!getShell().getEnabled());
                  w.close();
               }
            });
         }
      } 
      abstract protected void endOperationImpl();
   } 

Open in new window



1.  The operation can run any where from 6 seconds to over 20 seconds.  There is not a average time for the operation.

2.  So I had to set the Progress Bar up to run off and timer.
private static final int TOTAL_TIME = 10000;
 for (int total = 0; total < TOTAL_TIME ; total += INCREMENT)

Open in new window


3.  The problem is that the operation is running on 1 Thread and the progress bar is running on thread 2.  The two threads do not correspond together.  

4.  If the operation finishes before the progress bar timer is complete.  The progress bar runs in the background until the timer expires.  If the Progress Bar timer expires before the operation is complete.  The user thinks they can continue to work, but that is not true.

Someone suggested using a Condition in the progress bar and have the operation listener to update the condition when the operation is over.  So it will stop the Progress Bar thread.

Progress Bar Class with the Condition

Class ProgressBarThread implements IRunnableWithProgress
{
    private static final int TOTAL_TIME = 5000;
    private static final int INCREMENT = 1000;

    private Condition done = null;

    public ProgressBarThread(Condition done)
    {
        this.done = done;
    }

    public void run(IProgressMonitor monitor) throws InvocationTargetException,InterruptedException
    {
        monitor.beginTask("Sending Plot", IProgressMonitor.UNKNOWN);
        for (int total = 0; total < TOTAL_TIME ; total += INCREMENT)
        {
            if (done.await(INCREMENT, TimeUnit.MILLISECONDS))
            {
                break;
            }
            monitor.worked(INCREMENT);
            if (total == TOTAL_TIME / 2) monitor.subTask("Please be patient... Operation should finish soon.");
        }
        monitor.done();
    }
}

Open in new window


Then doing this to the operation class

AplotPlotterDialog w = null;

Condition done = null;

public MyOperationListener(AplotPlotterDialog win)
{
    w = win;
    Lock lock = new ReentrantLock();
    done = lock.newCondition();
} 

public void startProgressBar()
{
    try
    {
        new ProgressMonitorDialog(getShell()).run(true, false,
        new ProgressBarThread(done));
    } 
    catch (InvocationTargetException e)
    {
        MessageDialog.openError(getShell(), "Error", e.getMessage());
    }  
    catch (InterruptedException e)
    {
        MessageDialog.openInformation(getShell(), "Cancelled", e.getMessage());
    }
}

public void endOperation()
{
    try
    {
        endOperationImpl();
    }
    finally
    {
        Display.getDefault().asyncExec(new Runnable() {
        public void run() {
        w.getShell().setCursor(new Cursor(Display.getCurrent(), SWT.CURSOR_ARROW));
        w.recursiveSetEnabled(getShell(), true);
        w.getShell().setEnabled(!getShell().getEnabled());
        done.signal();
        w.close();
    }
    });
    }
}

Open in new window


But I can not get this to work.  The operation listener has to have a startOperation Method and the code above has replaced.

Any Help of This?
Avatar of krakatoa
krakatoa
Flag of United Kingdom of Great Britain and Northern Ireland image

3.  The problem is that the operation is running on 1 Thread and the progress bar is running on thread 2.  The two threads do not correspond together.  

Why not? They should; then your problem will be over. Set a flag.
Avatar of jkteater

ASKER

Please show me how to set a flag.  I have three over places in my project that is having the same problem with  the threads, so that would be such a great help to me.
Well normally as you know, a thread will end when the run method is over. Leaving aside the deprecated termination options, a thread's run() method is best halted by a boolean conditional being set to false, and that's all a flag is. So another thread can set that flag either directly (boolean stoprunning  = true (for example)) or indirectly via a setter method doing the same thing.
How about when the code is like this?

I have 3 classes.

Dialog Class
Operation Class
Progress Class

Dialog Class - Method to start long running operation

private void startPrinterListOperation() {
      listOp = new AplotPrinterListOperation(appReg.getString("aplot.message.GETPRINTERLIST"), session);
      listOp.addOperationListener(new AplotOperationListener(this) {
         public void endOperationImpl() {
            try { etc......

Open in new window


Adding the OperationListener to the operation

listOp.addOperationListener(new AplotOperationListener(this) {

Open in new window


public abstract class AplotOperationListener implements InterfaceAIFOperationListener {
   Dialog w = null;
  
   public AplotOperationListener(Dialog dialog) {
      w = dialog;
   } 

   public void startOperation(String startMessage) {
      Display.getDefault().asyncExec(new Runnable() {
         public void run() {
            w.getShell().setCursor(new Cursor(Display.getCurrent(), SWT.CURSOR_WAIT));
            w.getShell().setEnabled(false);
         }
      });
   } 
public void endOperation() {
      try { etc.......

Open in new window


Can I start the PorgressBar class from the OperationListener Class?

Something like :

public abstract class AplotOperationListener implements InterfaceAIFOperationListener {
   Dialog w = null;
  
   public AplotOperationListener(Dialog dialog) {
      w = dialog;
   } 
   
   public void startProgressBar() {
      try {
         new ProgressMonitorDialog(getShell()).run(true, false,
            new ProgressBar());
      } 
      catch (InvocationTargetException e) {
         MessageDialog.openError(getShell(), "Error", e.getMessage());
      } 
      catch (InterruptedException e) {
         MessageDialog.openInformation(getShell(), "Cancelled", e.getMessage());
      }
   }

   public void startOperation(String startMessage) {
      Display.getDefault().asyncExec(new Runnable() {
         public void run() {
            startProgressBar();
            w.getShell().setCursor(new Cursor(Display.getCurrent(), SWT.CURSOR_WAIT));
            w.getShell().setEnabled(false);
         }
      });
   } 

Open in new window


Then some how set a flag for progressbar to stop when the operationlistener closes the dialog


I really need some help with the above.  Can you please show some code to help me understand better?
ASKER CERTIFIED SOLUTION
Avatar of krakatoa
krakatoa
Flag of United Kingdom of Great Britain and Northern Ireland image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
I am not using swing.  My code is in SWT.