About JDK-6772009

David Holmes david.holmes at oracle.com
Thu Jan 5 04:48:47 UTC 2017


Hi,

You seem to be looking at an older version of the test code.

As I said in my previous mail I think the problem is that an interrupted 
thread can follow this path:

    if (!interrupted) {
       if (print)
          System.out.printf("completed after %d millis%n", 
                           NANOSECONDS.toMillis(System.nanoTime() - 
startTime));
       lock.lock();
       try {
          ++completed;
       }
       finally {
          lock.unlock();
       }
     }

because interrupted is only set when InterruptedException is caught:

while (!done || Thread.currentThread().isInterrupted()) {
     try {
         lock.lockInterruptibly();
     }
     catch (InterruptedException ie) {
         interrupted = true;

but we can also exit the loop due to interruption, without recording the 
fact we were interrupted. In which case the completed count will be too 
high.

Cheers,
David

On 5/01/2017 2:39 PM, chen zero wrote:
> Hi David,
> Thank you for reminding.
> I post the code here.
>
>
> import java.util.Arrays;
> import java.util.Collections;
> import java.util.Random;
> import java.util.concurrent.BrokenBarrierException;
> import java.util.concurrent.CyclicBarrier;
> import java.util.concurrent.locks.ReentrantLock;
>
> // https://bugs.openjdk.java.net/browse/JDK-6772009
>
> public final class CancelledLockLoops {
>     static final Random rng = new Random();
>     static boolean print = false;
>     //static final int ITERS = 1000000;
>     static final int ITERS = 10000000;
>
>     static final long TIMEOUT = 100;
>
>     public static void main(String[] args) throws Exception {
>         int maxThreads = 5;
>         if (args.length > 0) {
>             maxThreads = Integer.parseInt(args[0]);
>         }
>
>         print = true;
>
>         for (int i = 2; i <= maxThreads; i += (i+1) >>> 1) {
>             System.out.print("Threads: " + i);
>
>             try {
>                 new ReentrantLockLoop(i).test();
>             }
>             catch (BrokenBarrierException bb) {
>                 // OK, ignore
>                 bb.printStackTrace();
>             }
>             Thread.sleep(TIMEOUT);
>         }
>     }
>
>     static final class ReentrantLockLoop implements Runnable {
>         private int v = rng.nextInt();
>         private int completed;
>         private volatile int result = 17;
>         private final ReentrantLock lock = new ReentrantLock();
>         private final LoopHelpers.BarrierTimer timer = new
> LoopHelpers.BarrierTimer();
>         private final CyclicBarrier barrier;
>         private final int nthreads;
>
>         ReentrantLockLoop(int nthreads) {
>             this.nthreads = nthreads;
>             barrier = new CyclicBarrier(nthreads+1, timer);
>         }
>
>         void checkBarrierStatus() {
>             if(this.barrier.isBroken()) {
>                 throw new Error("barrier is broken !!!");
>             }
>         }
>
>         final void test() throws Exception {
>             checkBarrierStatus();
>
>             timer.run();
>
>             Thread[] threads = new Thread[nthreads];
>             for (int i = 0; i < threads.length; ++i) {
>                 threads[i] = new Thread(this, "th"+i);
>             }
>
>             for (int i = 0; i < threads.length; ++i) {
>                 threads[i].start();
>             }
>
>             Thread[] cancels =  (Thread[])(threads.clone());
>
>             Collections.shuffle(Arrays.asList(cancels), rng);
>             Thread.sleep(TIMEOUT);
>             for (int i = 0; i < cancels.length-2; ++i) {
>                 cancels[i].interrupt();
>                 // make sure all OK even when cancellations spaced out
>                 if ((i & 3) == 0) {
>                     Thread.sleep(1 + rng.nextInt(10));
>                 }
>             }
>
>             Thread.sleep(TIMEOUT);
>
>             try {
>                 // in here, the barrier might be broken because some
> working threads is interrupted.
>                 // so, catching the BrokenBarrierException to let
> testcase continue running
>                 barrier.await();
>             }
>             catch(BrokenBarrierException e) {
>                 // nop
>             }
>
>             if (print) {
>                 // since the barrier might be broken ( the barrier
> action will not run),
>                 // running here to ensure time is set.
>                 timer.run();
>                 long time = timer.getTime();
>                 double secs = (double)(time) / 1000000000.0;
>                 System.out.println("\t " + secs + "s run time");
>             }
>
>             int c;
>             lock.lock();
>             //System.out.println("main to verify completed.....");
>
>             try {
>                 c = completed;
>             }
>             finally {
>                 lock.unlock();
>             }
>             // here the completed should not < 2, it can not guarantee
> that always == 2.
>             if (c < 2) {
>                 throw new Error("Completed < 2 : " + c);
>             }
>
>             int r = result;
>             if (r == 0) { // avoid overoptimization
>                 System.out.println("useless result: " + r);
>             }
>         }
>
>         public final void run() {
>             try {
>                 checkBarrierStatus();
>
>                 int sum = v;
>                 int x = 0;
>                 int n = ITERS;
>                 do {
>                     try {
>                         lock.lockInterruptibly();
>                     }
>                     catch (InterruptedException ie) {
>                         break;
>                     }
>                     try {
>                         v = x = LoopHelpers.compute1(v);
>                     }
>                     finally {
>                         lock.unlock();
>                     }
>                     sum += LoopHelpers.compute2(x);
>                 } while (n-- > 0);
>
>                 /*
>                  * in the main thread, two threads are un-interrupted,
> others threads are interrupted.
>                  * this line, however, can not guarantee that only
> "un-interrupted" threads can go in,
>                  * but also interrupted threads can go in,
>                  * so, the "completed" will not always == 2, might be > 2
>                  */
>                 if (n < 0) {
>                     lock.lock();
>                     try {
>                         ++completed;
>                     }
>                     finally {
>                         lock.unlock();
>                     }
>                 }
>
>                 result += sum;
>                 barrier.await();
>             }
>             catch(BrokenBarrierException ex) {
>                 //ex.printStackTrace();
>             }
>             catch(InterruptedException ex) {
>                 //ex.printStackTrace();
>             }
>             catch (Exception ex) {
>                 ex.printStackTrace();
>                 return;
>             }
>         }
>     }
>
> }
>
>
> On Thu, Jan 5, 2017 at 12:20 PM, David Holmes <david.holmes at oracle.com
> <mailto:david.holmes at oracle.com>> wrote:
>
>     Hi chenzero,
>
>     Attachments get stripped from the mailing lists so you'll need to
>     include your patch inline, or else get someone to host it for you on
>     cr.openjdk.java.net <http://cr.openjdk.java.net>
>
>     Thanks,
>     David
>     .....
>


More information about the core-libs-dev mailing list