jkteater
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.
At the very start of the method I am Starting the Progress Bar in a separate thread.
Method for ProgressBar
ProgressBar Class
Then the listener is added to the long running operation. See Method Above
MyOperationListener Class
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.
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
Then doing this to the operation class
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?
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()
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();
}
});
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());
}
}
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();
}
Then the listener is added to the long running operation. See Method Above
saveOp.addOperationListener(new MyOperationListener(this)
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();
}
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)
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();
}
}
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();
}
});
}
}
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?
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.
ASKER
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
Adding the OperationListener to the operation
Can I start the PorgressBar class from the OperationListener Class?
Something like :
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?
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......
Adding the OperationListener to the operation
listOp.addOperationListener(new AplotOperationListener(this) {
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.......
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);
}
});
}
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
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
ASKER
I am not using swing. My code is in SWT.
Why not? They should; then your problem will be over. Set a flag.