Re: ForkJoin refresh

Peter Levart via Concurrency-interest <[email protected]>
Newsgroups gmane.comp.java.jsr.166-concurrency
Message-ID <[email protected]>
Ooops,

There's also a race at the beginning of task execution. The task might 
already be executing and another thread might call cancel(true) even 
before the 'runner' field is set. In this case, the code of task will 
not get interrupted. So we should check the cancelation status after 
setting the 'runner' field and bail out if it was canceled.

This might do:

     static final class AdaptedInterruptibleCallable<T> extends 
ForkJoinTask<T>
         implements RunnableFuture<T> {
         @SuppressWarnings("serial") // Conditionally serializable
         final Callable<? extends T> callable;
         transient volatile Thread runner;
         transient volatile boolean cancelInterrupted;
         @SuppressWarnings("serial") // Conditionally serializable
         T result;

         AdaptedInterruptibleCallable(Callable<? extends T> callable) {
             if (callable == null) throw new NullPointerException();
             this.callable = callable;
         }

         public final T getRawResult() { return result; }

         public final void setRawResult(T v) { result = v; }

         public final boolean exec() {
             Thread t = Thread.currentThread();
             // set runner filed
             runner = t;
             try {
                 // check for concurrent cancel() that just missed the 
runner field
                 if (isCancelled()) {
                     throw new CancellationException();
                 } else {
                     result = callable.call();
                 }
                 return true;
             } catch (RuntimeException rex) {
                 throw rex;
             } catch (Exception ex) {
                 throw new RuntimeException(ex);
             } finally {
                 if (!RUNNER.compareAndSet(this, t, (Thread) null)) {
                     // someone called cancel(true) and successfully CASed
                     // runner to null - we should wait for it to set the
                     // cancelInterrupted flag...
                     while (!cancelInterrupted) {
                         Thread.onSpinWait();
                     }
                     // ... and then clear the interrupt it set just 
before that
                     Thread.interrupted();
                 }
             }
         }

         public final void run() { invoke(); }

         public final boolean cancel(boolean mayInterruptIfRunning) {
             Thread t;
             boolean stat = super.cancel(false);
             if (mayInterruptIfRunning && (t = runner) != null &&
                 RUNNER.compareAndSet(this, t, (Thread) null)) {
                 try {
                     t.interrupt();
                 } catch (Throwable ignore) {
                 }
                 cancelInterrupted = true;
             }
             return stat;
         }

         public String toString() {
             return super.toString() + "[Wrapped task = " + callable + "]";
         }

         private static final VarHandle RUNNER;
         static {
             try {
                 RUNNER = MethodHandles
                     .lookup()
.findVarHandle(AdaptedInterruptibleCallable.class, "runner", Thread.class);
             } catch (NoSuchFieldException | IllegalAccessException e) {
                 throw new InternalError(e);
             }
         }

         private static final long serialVersionUID = 2838392045355241008L;
     }


Regards, Peter

_______________________________________________
Concurrency-interest mailing list
[email protected]
http://cs.oswego.edu/mailman/listinfo/concurrency-interest
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.