У меня общий вопрос, когда несколько семафоров накладываются друг на друга - как правильно обрабатывать исключения для таких ситуаций в контексте блоков try
и finally
.
В приведенном ниже коде есть два семафора sP
и sC
, которые используются для указания полноты и пустоты стека соответственно. lock
служит мьютексом для критической секции.
Как правильно обрабатывать исключения с семафорами sP
и sC
, сложенными с семафором lock
. Кажется, что исключения в блоках try
должны обрабатываться более осторожно для семафоров sP
и sC
, и если это так, каков будет чистый способ обработки их правильного освобождения? Нужно ли мне отдельное вложение try
/ finally
, и если да, то как учесть сбои во внутреннем блоке try
.
Хотя ниже приведено в java, это вопрос общего параллелизма, т.е. не спецификация языка c.
import java.util.concurrent.Semaphore;
class Buffer {
Semaphore sC;
Semaphore sP;
Semaphore lock;
int capacity;
int count;
int[] s; // FIFO stack
public int get() throws InterruptedException {
int tmp = -1;
sC.acquire();
lock.acquire();
try {
if(count>0) {
count-=1;
tmp = s[count];
}
} catch (Exception e) {
e.printStackTrace();
} finally {
System.out.println("Get: "+tmp);
lock.release();
sP.release();
}
return tmp;
}
public void put(int i) throws InterruptedException {
sP.acquire();
lock.acquire();
try {
if(count<capacity){
s[count]=i;
count+=1;
}
} catch (Exception e) {
e.printStackTrace();
} finally {
System.out.println("Put: "+i);
lock.release();
sC.release();
}
}
Buffer(int numItems) {
capacity = numItems;
sP = new Semaphore(numItems);
sC = new Semaphore(0);
lock = new Semaphore(1);
s = new int[numItems];
}
}
Редактировать После Йоханнес Кун подсказка:
public int get() throws InterruptedException {
int tmp = -1;
sC.acquire();
try {
lock.acquire();
try {
if(count>0) {
count-=1;
tmp = s[count];
}
} catch (Exception e) {
e.printStackTrace();
} finally {
System.out.println("Get: "+tmp);
lock.release();
}
} catch (Exception e) {
sC.release();
} finally {
sP.release();
}
return tmp;
}
public void put(int i) throws InterruptedException {
sP.acquire();
try {
lock.acquire();
try {
if(count<capacity){
s[count]=i;
count+=1;
}
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.release();
}
} catch (Exception e) {
sP.release();
} finally {
sC.release();
}
}
Редактировать 2: После еще одного из Йоханнес Кун подсказка: (изменено, чтобы отразить то же вложение, что и в put()
)
public int get() throws InterruptedException {
int tmp = -1;
boolean lockException = false;
sC.acquire();
try {
lock.acquire();
try {
if(count>0) {
count-=1;
tmp = s[count];
}
return tmp;
} catch (Exception e) {
e.printStackTrace();
} finally {
System.out.println("Get: "+tmp);
lock.release();
}
} catch (Exception e) {
sC.release();
lockException = true;
} finally {
if (!lockException) {
sP.release();
}
}
return -1;
}
public void put(int i) throws InterruptedException {
boolean lockException = false;
sP.acquire();
try {
lock.acquire();
try {
if(count<capacity){
s[count]=i;
count+=1;
}
} catch (Exception e) {
e.printStackTrace();
} finally {
System.out.println("Put: "+i);
lock.release();
}
} catch (Exception e) {
sP.release();
lockException = true;
} finally {
if (!lockException) {
sC.release();
}
}
}
}