Ожидание завершения всех Runnables, отправленных в поток пользовательского интерфейса SWT с помощью Display :: asyncExec () - PullRequest
4 голосов
/ 21 ноября 2011

Есть ли способ дождаться завершения всех Runnables, отправленных в поток пользовательского интерфейса SWT через asyncExec (...)?

Фон:

У меня естьдлительная операция, которая, помимо прочего, инициирует события, которые, в свою очередь, передают Runnables потоку пользовательского интерфейса SWT через метод экземпляра asyncExec (...) Display.

Ход выполнения длительной операцииотображается в ProgressMonitorDialog, и я хотел бы закрыть диалог только после того, как поток пользовательского интерфейса завершил выполнение Runnables.

Изменение вызовов от asyncExec (...) к syncExec (...) невариант, так как последний нежелателен, когда события инициируются из других контекстов.

Ответы [ 2 ]

7 голосов
/ 21 ноября 2011

org.eclipse.swt.widgets.Display.readAndDispatch() обработает событие из очереди событий и вернет false, если больше нет событий для обработки. Но вы, вероятно, не хотите использовать это, поскольку оно обрабатывает событие.

asyncExec(*) - это очередь FIFO (хотя графические события ОС заменяют asyncExecs), поэтому вы можете выполнить большую часть длительной обработки операций, а затем поместить окончательный asyncExec в очередь:

final boolean[] done = new boolean[1];
Runnable r = new Runnable() {
  public void run() {
    done[0] = true;
  }
};
// now wait for the event somehow.  The brute force method:
while (!done[0]) {
  Thread.sleep(200);
}

Теоретически, все другие asyncExecs, порожденные вашей длительной операцией, будут завершены к тому времени, когда вы доберетесь до последней.

РЕДАКТИРОВАТЬ : возможный другой вариант

Создайте свой собственный org.eclipse.core.runtime.jobs.Job, а затем join() в конце:

public static class RefCountJob extends Job {
    public RefCountJob() {
        super("REF_COUNT");
    }

    int count = 0;

    public void increment() {
        count++;
    }

    public void decrement() {
        count--;
    }

    @Override
    protected IStatus run(IProgressMonitor monitor) {
        monitor.beginTask("WAITING", IProgressMonitor.UNKNOWN);
        while (count > 0) {
            Thread.sleep(200);
            monitor.worked(1);
        }
        monitor.done();
        return Status.OK_STATUS;
    }
}

Чтобы использовать его, увеличивайте () его каждый раз, когда вы собираетесь запускать события, и заставляйте их уменьшать его, когда они сделаны (вы должны убедиться, что они уменьшают его независимо от того, какое исключение выдается: -)

RefCountJob ref = new RefCountJob();
// ... do stuff, everybody increments and decrements ref
ref.increment();
// ... do more stuff
ref.increment();
// at the end of your long-running job
ref.schedule();
ref.join();
3 голосов
/ 25 ноября 2011

Спасибо, я закончил со следующим.Я думаю, что это довольно чистое решение.Кстати, я бы одобрил ваш ответ, если бы у меня было достаточно репутации для этого:)

public class SWTThreadingUtils
{

    public static void waitForAsyncExecsToFinish(Display display)
    {
        Object waitObj = new Object();

        display.asyncExec(new DummyRunnable(waitObj));
        synchronized (waitObj) 
        {
            try {
                waitObj.wait();

            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }
    }


    private static class DummyRunnable implements Runnable
    {
        private Object waitObj;

        public DummyRunnable(Object waitObj)
        {
            this.waitObj = waitObj;
        }

        @Override
        public void run()
        {
            synchronized (waitObj)
            {
                waitObj.notify();
            }
        }    
    }

}
...