1

I've been using Java for a few years, but my thread knowledge is rubbish. I've Googled pretty heavily and found some good information about general use of ProgressMonitorDialog but nothing like my exact circumstances.

I'm currently using a ProgressMonitorDialog as a wrapper around an instance of IRunnableWithProgress, which in turn is a wrapper around a Thread. This works fine but now I'm trying to make the cancel button trigger an interrupt on the running thread, which I can handle to gracefully terminate the operation.

One important thing to note is that I have two plugins; "Data" and "UI". The data plugin contains all of the real work, and must be independent from the UI or any Eclipse plugins. The UI plugin should be as thin as possible.

Here's a distilled version of the code I've got so far.

Data:

public class Data {
    public static Thread createThread() {
        return new Thread() {
            @Override
            public void run() {
                Thing t = new Thing();
                t.operationA();
                t.operationB();
                t.operationC();
            }
        }
    }
}

UI:

public class UI {

    public void doOperation() {
        try {
            new ProgressMonitorDialog(getShell()).run(true, true, new MyOperation());
        }
        catch (Exception e) {
            e.printStatckTrace();
        }
    }

    public class MyOperation implements IRunnableWithProgress {

        @Override
        public void run(IProgressMonitor monitor) throws InterruptedException, InvocationTargetException {

            monitor.beginTask("Task", 2);

            try {
                Thread myThread = Data.createThread();
                myThread.start();
                monitor.worked(1);

                while (myThread.isAlive() && !monitor.isCanceled()) {}

                if (monitor.isCanceled()) {
                    myThread.interrupt();
                }

                monitor.worked(1);

            }
            finally {
                monitor.done();
            }
        }
    }

}

So when the cancel button is clicked, myThread.interrupt() is called. Now the thread needs to respond to the interrupt. Data.createThread() now looks something like this:

public static Thread createThread() {
    return new Thread() {
        @Override
        public void run() {

            Thing t = new Thing();

            t.operationA();

            if (Thread.currentThread.isInterrupted()) {
                // Tidy up
                return;
            }

            t.operationB();

            if (Thread.currentThread.isInterrupted()) {
                // Tidy up
                return;
            }

            t.operationC();

            if (Thread.currentThread.isInterrupted()) {
                // Tidy up
                return;
            }
        }
    }
}

It might be rather verbose polling the interrupted state like this, but I can't see this causing any problems.

But, what if Thing.operationA() wasn't atomic, and could be interrupted within that function:

public class Thing {
    public void operationA() {
        atomic1();
        // How would I detect and handle a change to the interrupted state here?
        atomic2();
    }
    public void operationB() {
        // One atomic operation
    }
    public void operationC() {
        // One atomic operation
    }
}

How would I detect and handle a change to the interrupted state between atomic1() and atomic2()? Is it as simple as polling Thread.currentThread.isInterrupted() again? Or will I need to pass around some volatile object to track the interrupted state? Should I be throwing InterruptedException somewhere?

My second question is about tracking and reporting progress. I understand how IProgressMonitor.worked() should be used. As already seen, my Data thread contains 3 operations. Is it possible to pass that information up to the UI so I can track the progress in the ProgressMonitorDialog?

Ideally, something like this:

public static Thread createThread() {
    return new Thread() {
        @Override
        public void run(IProgressMonitor monitor) {

            Thing t = new Thing();

            t.operationA();

            monitor.worked(1);

            if (Thread.currentThread.isInterrupted()) {
                // Tidy up
                return;
            }

            t.operationB();

            monitor.worked(1);

            if (Thread.currentThread.isInterrupted()) {
                // Tidy up
                return;
            }

            t.operationC();

            monitor.worked(1);

            if (Thread.currentThread.isInterrupted()) {
                // Tidy up
                return;
            }
        }
    }
}

However as stated, Data cannot depend on Eclipse and therefore passing the IProgressMonitor doesn't work in this case.

Could I have a variable tracking progress in my thread, and then call something like myThread.getProgress() asynchronously from the UI thread to update the progress bar with new work? I'm not sure how feasible this is (it popped into my head as I was writing this question) so I'll try that next.

Lots of information and question marks in here, sorry if my style is a bit scattered. I could elaborate more if needs be but this is already a wall of text. Any information, advice or ideas appreciated.

4

1 に答える 1

1

との間 で、キャンセルの場合のクリーンアップを確認する必要がありますatomic1()。必要なものを処理する場合、例外をスローする必要はありません。atomic2()Thread.currentThread.isInterrupted()

進行状況の追跡に関しては、Data プラグインで独自のリスナー オブジェクトを作成し、それをスレッドに渡すことができます。UI はそれをインスタンス化し、スレッドに渡します。このようにして、データは依存関係なしで進捗イベントを UI に渡すことができます。

于 2015-07-26T06:21:46.580 に答える