diff options
author | Sven Gothel <[email protected]> | 2015-09-12 17:29:31 +0200 |
---|---|---|
committer | Sven Gothel <[email protected]> | 2015-09-12 17:29:31 +0200 |
commit | 2b97ed6d238a0db1e2cf7bdf15349e90eaaa8dfc (patch) | |
tree | af8429652c07fae310cd2b85921667126019904f | |
parent | 47495cd2a228534578731346c8baf2b190bcd241 (diff) |
Bug 1213 (related): Fix TaskBase, RunnableTask and FunctionTask implementation and semantics
- TaskBase
- requires 'volatile boolean isExecuted' for atomic query of same semantics
- fix isInQueue(): condition was reverse in regars to 'isExecuted'
- expose 'Thread getExecutionThread()' as learned within run() method.
- RunnableTask
- deprecate: 'static invoke(final boolean waitUntilDone, final Runnable runnable)',
since it's nonsense, use runnable.run() instead.
- 'static RunnableTask invokeOnNewThread(..)'
- uses InterruptSource.Thread
- Persistent-Wait
- Cancelable using InterruptedRuntimeException
- FunctionTask
- deprecate 'static <U,V> U invoke(final boolean waitUntilDone, final Function<U,V> func, final V... args)',
since it's nonsense, use func.eval(args) instead.
- 'static FunctionTask<U,V> invokeOnNewThread(..)'
- uses InterruptSource.Thread
- Persistent-Wait
- Cancelable using InterruptedRuntimeException
-rw-r--r-- | src/java/com/jogamp/common/util/FunctionTask.java | 68 | ||||
-rw-r--r-- | src/java/com/jogamp/common/util/RunnableTask.java | 90 | ||||
-rw-r--r-- | src/java/com/jogamp/common/util/TaskBase.java | 15 |
3 files changed, 101 insertions, 72 deletions
diff --git a/src/java/com/jogamp/common/util/FunctionTask.java b/src/java/com/jogamp/common/util/FunctionTask.java index 4ac64d3..5a58a34 100644 --- a/src/java/com/jogamp/common/util/FunctionTask.java +++ b/src/java/com/jogamp/common/util/FunctionTask.java @@ -30,6 +30,8 @@ package com.jogamp.common.util; import java.io.PrintStream; +import com.jogamp.common.JogampRuntimeException; + /** * Helper class to provide a Runnable queue implementation with a Runnable wrapper * which notifies after execution for the <code>invokeAndWait()</code> semantics. @@ -40,34 +42,54 @@ public class FunctionTask<R,A> extends TaskBase implements Function<R,A> { protected A[] args; /** - * Invokes <code>func</code>. + * @deprecated Simply invoke {@link Function#eval(Object...)} + */ + public static <U,V> U invoke(final boolean waitUntilDone, final Function<U,V> func, final V... args) { + return func.eval(args); + } + + /** + * Invokes <code>func</code> on a new thread belonging to the given {@link ThreadGroup}. + * <p> + * The result can be retrieved via {@link FunctionTask#getResult()}, + * using the returned instance. + * </p> + * @param tg the {@link ThreadGroup} for the new thread, maybe <code>null</code> + * @param threadName the name for the new thread * @param waitUntilDone if <code>true</code>, waits until <code>func</code> execution is completed, otherwise returns immediately. * @param func the {@link Function} to execute. * @param args the {@link Function} arguments - * @return the {@link Function} return value + * @return the newly created and invoked {@link FunctionTask} */ - public static <U,V> U invoke(final boolean waitUntilDone, final Function<U,V> func, final V... args) { - Throwable throwable = null; - final Object sync = new Object(); - final FunctionTask<U,V> rt = new FunctionTask<U,V>( func, waitUntilDone ? sync : null, true, waitUntilDone ? null : System.err ); - final U res; - synchronized(sync) { - res = rt.eval(args); - if( waitUntilDone ) { - try { - sync.wait(); - } catch (final InterruptedException ie) { - throwable = ie; - } - if(null==throwable) { - throwable = rt.getThrowable(); - } - if(null!=throwable) { - throw new RuntimeException(throwable); + public static <U,V> FunctionTask<U,V> invokeOnNewThread(final ThreadGroup tg, final String threadName, + final boolean waitUntilDone, final Function<U,V> func, final V... args) { + final FunctionTask<U,V> rt; + if( !waitUntilDone ) { + rt = new FunctionTask<U,V>( func, null, true, System.err ); + final InterruptSource.Thread t = new InterruptSource.Thread(tg, rt, threadName); + rt.args = args; + t.start(); + } else { + final Object sync = new Object(); + rt = new FunctionTask<U,V>( func, sync, true, null ); + final InterruptSource.Thread t = new InterruptSource.Thread(tg, rt, threadName); + synchronized(sync) { + rt.args = args; + t.start(); + while( rt.isInQueue() ) { + try { + sync.wait(); + } catch (final InterruptedException ie) { + throw new InterruptedRuntimeException(ie); + } + final Throwable throwable = rt.getThrowable(); + if(null!=throwable) { + throw new JogampRuntimeException(throwable); + } } } } - return res; + return rt; } /** @@ -124,6 +146,8 @@ public class FunctionTask<R,A> extends TaskBase implements Function<R,A> { */ @Override public final void run() { + execThread = Thread.currentThread(); + final A[] args = this.args; this.args = null; this.result = null; @@ -144,6 +168,7 @@ public class FunctionTask<R,A> extends TaskBase implements Function<R,A> { } } finally { tExecuted = System.currentTimeMillis(); + isExecuted = true; } } else { synchronized (syncObject) { @@ -161,6 +186,7 @@ public class FunctionTask<R,A> extends TaskBase implements Function<R,A> { } } finally { tExecuted = System.currentTimeMillis(); + isExecuted = true; syncObject.notifyAll(); } } diff --git a/src/java/com/jogamp/common/util/RunnableTask.java b/src/java/com/jogamp/common/util/RunnableTask.java index 6fb98de..69d7af2 100644 --- a/src/java/com/jogamp/common/util/RunnableTask.java +++ b/src/java/com/jogamp/common/util/RunnableTask.java @@ -30,6 +30,8 @@ package com.jogamp.common.util; import java.io.PrintStream; +import com.jogamp.common.JogampRuntimeException; + /** * Helper class to provide a Runnable queue implementation with a Runnable wrapper * which notifies after execution for the <code>invokeAndWait()</code> semantics. @@ -38,30 +40,18 @@ public class RunnableTask extends TaskBase { protected final Runnable runnable; /** - * Invokes <code>runnable</code> on the current thread. - * @param waitUntilDone if <code>true</code>, waits until <code>runnable</code> execution is completed, otherwise returns immediately. - * @param runnable the {@link Runnable} to execute. + * @deprecated Simply invoke {@link Runnable#run()} */ public static void invoke(final boolean waitUntilDone, final Runnable runnable) { - Throwable throwable = null; - final Object sync = new Object(); - final RunnableTask rt = new RunnableTask( runnable, waitUntilDone ? sync : null, true, waitUntilDone ? null : System.err ); - synchronized(sync) { - rt.run(); - if( waitUntilDone ) { - try { - sync.wait(); - } catch (final InterruptedException ie) { - throwable = ie; - } - if(null==throwable) { - throwable = rt.getThrowable(); - } - if(null!=throwable) { - throw new RuntimeException(throwable); - } - } - } + runnable.run(); + } + + /** + * @deprecated Use {@link #invokeOnNewThread(ThreadGroup, String, boolean, Runnable)} + */ + public static Thread invokeOnNewThread(final ThreadGroup tg, final boolean waitUntilDone, final Runnable runnable, final String threadName) { + final RunnableTask rt = invokeOnNewThread(tg, threadName, waitUntilDone, runnable); + return rt.getExecutionThread(); } /** @@ -71,37 +61,37 @@ public class RunnableTask extends TaskBase { * @param runnable the {@link Runnable} to execute on the new thread. If <code>waitUntilDone</code> is <code>true</code>, * the runnable <b>must exist</b>, i.e. not loop forever. * @param threadName the name for the new thread - * @return the newly created {@link Thread} + * @return the newly created and invoked {@link RunnableTask} */ - public static Thread invokeOnNewThread(final ThreadGroup tg, final boolean waitUntilDone, final Runnable runnable, final String threadName) { - final Thread t = new Thread(tg, threadName) { - @Override - public void run() { - Throwable throwable = null; - final Object sync = new Object(); - final RunnableTask rt = new RunnableTask( runnable, waitUntilDone ? sync : null, true, waitUntilDone ? null : System.err ); - synchronized(sync) { - rt.run(); - if( waitUntilDone ) { - try { - sync.wait(); - } catch (final InterruptedException ie) { - throwable = ie; - } - if(null==throwable) { - throwable = rt.getThrowable(); - } - if(null!=throwable) { - throw new RuntimeException(throwable); - } + public static RunnableTask invokeOnNewThread(final ThreadGroup tg, final String threadName, + final boolean waitUntilDone, final Runnable runnable) { + final RunnableTask rt; + if( !waitUntilDone ) { + rt = new RunnableTask( runnable, null, true, System.err ); + final InterruptSource.Thread t = new InterruptSource.Thread(tg, rt, threadName); + t.start(); + } else { + final Object sync = new Object(); + rt = new RunnableTask( runnable, sync, true, null ); + final InterruptSource.Thread t = new InterruptSource.Thread(tg, rt, threadName); + synchronized(sync) { + t.start(); + while( rt.isInQueue() ) { + try { + sync.wait(); + } catch (final InterruptedException ie) { + throw new InterruptedRuntimeException(ie); + } + final Throwable throwable = rt.getThrowable(); + if(null!=throwable) { + throw new JogampRuntimeException(throwable); } } - } }; - t.start(); - return t; + } + } + return rt; } - /** * Create a RunnableTask object w/ synchronization, * ie. suitable for <code>invokeAndWait()</code>, i.e. {@link #invoke(boolean, Runnable) invoke(true, runnable)}. @@ -126,6 +116,8 @@ public class RunnableTask extends TaskBase { @Override public final void run() { + execThread = Thread.currentThread(); + runnableException = null; tStarted = System.currentTimeMillis(); if(null == syncObject) { @@ -143,6 +135,7 @@ public class RunnableTask extends TaskBase { } } finally { tExecuted = System.currentTimeMillis(); + isExecuted = true; } } else { synchronized (syncObject) { @@ -160,6 +153,7 @@ public class RunnableTask extends TaskBase { } } finally { tExecuted = System.currentTimeMillis(); + isExecuted = true; syncObject.notifyAll(); } } diff --git a/src/java/com/jogamp/common/util/TaskBase.java b/src/java/com/jogamp/common/util/TaskBase.java index 59b86c3..518aeba 100644 --- a/src/java/com/jogamp/common/util/TaskBase.java +++ b/src/java/com/jogamp/common/util/TaskBase.java @@ -54,7 +54,9 @@ public abstract class TaskBase implements Runnable { protected Throwable runnableException; protected long tCreated, tStarted; protected volatile long tExecuted; + protected volatile boolean isExecuted; protected volatile boolean isFlushed; + protected volatile Thread execThread; protected TaskBase(final Object syncObject, final boolean catchExceptions, final PrintStream exceptionOut) { this.syncObject = syncObject; @@ -64,7 +66,9 @@ public abstract class TaskBase implements Runnable { tCreated = System.currentTimeMillis(); tStarted = 0; tExecuted = 0; + isExecuted = false; isFlushed = false; + execThread = null; } protected final String getExceptionOutIntro() { @@ -76,6 +80,11 @@ public abstract class TaskBase implements Runnable { } } + /** Returns the execution thread or {@code null} if not yet {@link #run()}. */ + public final Thread getExecutionThread() { + return execThread; + } + /** * Return the synchronization object if any. * @see #RunnableTask(Runnable, Object, boolean) @@ -126,12 +135,12 @@ public abstract class TaskBase implements Runnable { /** * @return !{@link #isExecuted()} && !{@link #isFlushed()} */ - public final boolean isInQueue() { return 0 != tExecuted && !isFlushed; } + public final boolean isInQueue() { return !isExecuted() && !isFlushed(); } /** * @return True if executed, otherwise false; */ - public final boolean isExecuted() { return 0 != tExecuted ; } + public final boolean isExecuted() { return isExecuted; } /** * @return True if flushed, otherwise false; @@ -159,7 +168,7 @@ public abstract class TaskBase implements Runnable { @Override public String toString() { - return "RunnableTask[executed "+isExecuted()+", tTotal "+getDurationTotal()+" ms, tExec "+getDurationInExec()+" ms, tQueue "+getDurationInQueue()+" ms, attachment "+attachment+", throwable "+getThrowable()+"]"; + return "RunnableTask[enqueued "+isInQueue()+"[executed "+isExecuted()+", flushed "+isFlushed()+"], tTotal "+getDurationTotal()+" ms, tExec "+getDurationInExec()+" ms, tQueue "+getDurationInQueue()+" ms, attachment "+attachment+", throwable "+getThrowable()+"]"; } } |