2

I have three threads and they need some resources to run (A,B,C) that I have implemented using Semaphores.

public void run(){
 while(!Thread.currentThread().isInterrupted){
  try{
    A.acquire(2);
    B.acquire(2);
    //some-stuff
  }
  catch(InterruptedException ex){}
  finally{ 
     A.release(2); //PROBLEM
     B.release(2);
         }
  }

Problem: while running, the thread could be interrupted but, going in the finally method I don't know where I was during the interruption so I don't know if I have to release something or not. I have tried a lot of different implementation, like using the method (boolean) tryAcquire() but another problem comes up: if I get the resource A but not the B, then in the finally block I would release the A again etc. Do you have any suggestions? Thank you.

nyi
  • 3,123
  • 4
  • 22
  • 45

2 Answers2

1

Use nested try blocks:

try {
    A.acquire(2);
    try {
        B.acquire(2);
        try {
            // some stuff
        } finally {
            B.release(2);
        }
    } finally {
        A.release(2);
    }
} catch (InterruptedException ex) {}
shmosel
  • 49,289
  • 6
  • 73
  • 138
0

You could try to use List like this:

List<Semaphore> acquired = new ArrayList<>(2);
while(!Thread.currentThread().isInterrupted) { 
  try{
    A.acquire(2);
    acquired.add(A);
    B.acquire(2);
    acquired.add(B);
    //some-stuff
  } catch(InterruptedException ex){}
  finally{ 
    for (Semaphore s : acquired) {
      s.release(2);
    }
    s.clear();
  }
}
Ivan
  • 8,508
  • 2
  • 19
  • 30
  • I think the question turns around "atomic statement". In your example, what if the interruption occours between A.acquire(2) and acquired.add(A) ? In the finally block 2 resources of A wouldn't be released. – alessandroAmedei May 22 '18 at 19:43
  • @alessandroAmedei if interruption occurs on `A.acquire(2)` then exception will be thrown and `finally` will be executed correctly (nothing was acquired, nothing to release). But if thread is interrupted between `acquire` and `acquired.add()` then no exception will be thrown and program will continue to execute and will add resource to the list – Ivan May 22 '18 at 19:51
  • thank you! Should this work? `code public void run() { while (!Thread.currentThread().isInterrupted()) { boolean a = false; boolean b = false; try { Main.A.acquire(2); a = true; Main.B.acquire(2); b = true; buffer.setAB(value); value++; Thread.sleep(1000); } catch (InterruptedException ex) { } finally { if (a) { Main.A.release(2); } if (b) { Main.B.release(2); } } } }` – alessandroAmedei May 22 '18 at 20:08
  • @alessandroAmedei I think yes. You could also write unit tests for your code for both normal execution and `InterruptedException` case – Ivan May 22 '18 at 20:11
  • I had to add `code Thread.currentThread().interrupt();` in the catch block if not it didn't work. Why? – alessandroAmedei May 22 '18 at 20:30
  • When `InterruptedException` is thrown thread's interrupted status is cleared that is why you will have endless loop. So you'd better use a `boolean` flag in `while` condition and set it to false in `catch`. Check this link for more details: https://stackoverflow.com/questions/2523721/why-do-interruptedexceptions-clear-a-threads-interrupted-status – Ivan May 22 '18 at 20:46
  • it didn't work because after the execution i checked the available resources in the semaphores and some of them were still busy. It was like that after the finally block some resources got acquire again. – alessandroAmedei May 22 '18 at 20:54