O
Olivier Merigon
Hello,
I have a concurency problem that I am not able to solve.
Let say that we have a thread that we want to cancel. The job of the thread
is to initiate transfers (with a delay between retry) until the transfer is
succeeded or canceled. Also there is a maximum number of thread that can run
at the same time. For this we have a monitor that enable us to limit the
number of simultaneous download (Monitor.begin() that wait until a slot is
available and Monitor.finish() that release a slot)
So the thread can be in 4 state: tranferring, sleepping (waiting delay),
Waiting for a slot, or doing someting else (initialisation...)
My goal is to be able to cancel the thread in the 4 situation without
blocking and to be sure the process is realy cancelled.
This is the version of my class without the concurency problems solved:
public class XferDownloadThread { //V1
String xferSate = INTERRUPTED;
boolean doCancel;
boolean sleeping;
boolean waitingSlot;
XferClient xferClient = null;
public void run() {
doJobInit;
do {
waitingSlot = true;
Monitor.begin();
waitingSlot = false;
if (doCancel) {
Monitor.finish();
return;
}
//<--------LINE A
xferClient = new XferClient()
xferState = xferClient.doTransfer();
Monitor.finish();
if (xferState == INTERRUPTED) {
sleepping = true;
sleep(delayTime);
sleeping = false;
}
} while (xferState == INTERRUPTED)
}
public void cancelXfer() {
doCancel = true;
xferSate = CANCELED;
if (sleeping || waitingSlot)
interrupt();
if (xferClient != null)
xferClient.cancel();
}
}
The first obvious problem is that if I try to cancel the xfer while the
thread is at line A, the transfer will be done anyway.
I solved it like this:
public class XferDownloadThread { //V2
String xferSate = INTERRUPTED;
boolean doCancel;
boolean sleeping;
boolean waitingSlot;
XferClient xferClient;
Object mutexXferClient = new Object();
public void run() {
doJobInit;
do {
waitingSlot = true;
Monitor.begin();
waitingSlot = false;
syncronized (mutexXferClient) {
if (doCancel) {
Monitor.finish();
return;
}
xferClient = new XferClient()
}
xferState = xferClient.doTransfer();
Monitor.finish();
if (xferState == INTERRUPTED) {
sleepping = true;
//<--------LINE B
sleep(delayTime);
//<--------LINEC
sleeping = false;
}
} while (xferState == INTERRUPTED)
}
public void cancelXfer() {
syncronized(mutexXferClient) {
doCancel = true;
xferSate = CANCELED;
if (sleeping || waitingSlot)
interrupt();
if (xferClient != null)
xferClient.cancel();
}
}
}
The second problem is of the same type at line B and C, if I try to cancel
the xfer while the thread is at this line, the interrupt statement will have
no effect and I will go inside the sleep statement anyway.
*********
I need to be sure that the thread is sleeping before calling interrupt() and
I want to be sure that if cancelXfer() has been called I wil not go to
sleep.
*********
I tried to solve it with the same design but it doesn't do the job (the
first case works because the call to the XferClient contructor will not
block, not like sleep and Monitor.begin()).
Let say that the run method acquire the mutexSleeping first, the
cancelXfer() call will block until the sleep() is over because we wait for
the mutexSleeping to be released and it will be released only at the end of
the sleep time. I don't want this to happen since I want the thread to be
canceled immediatly.
I don't know how to handle the problem.
The same design flaw will occur for line E and F and the Monitor.begin()
statement; I want to be sure that if I called cancelXfer() I will not try to
acquire a monitor slot.
I know that these problems may never occur, but I can't leave it like this.
If anybody have a solution to my problem thanks in advance...
public class XferDownloadThread { //V3
String xferSate = INTERRUPTED;
boolean doCancel;
boolean sleeping;
XferClient xferClient;
Object mutexXferClient = new Object();
Object mutexSleeping = new Object();
public void run() {
doJobInit;
do {
waitingSlot = true;
//<---------LINE E
Monitor.begin();
//<---------LINE F
waitingSlot = false;
syncronized (mutexXferClient) {
if (doCancel) {
Monitor.finish();
return;
}
xferClient = new XferClient()
}
xferState = xferClient.doTransfer();
Monitor.finish();
if (xferState == INTERRUPTED) {
syncronized (mutexSleeping) {
if (doCancel)
return;
sleeping = true;
sleep(delayTime);
sleeping = false;
}
}
} while (xferState == INTERRUPTED)
}
public void cancelXfer() {
syncronized(mutexSleeping) {
syncronized(mutexXferClient) {
xferSate = CANCELED;
doCancel = true;
if (sleeping)
interrupt();
if (xferClient != null)
xferClient.cancel();
}
}
}
Olivier
I have a concurency problem that I am not able to solve.
Let say that we have a thread that we want to cancel. The job of the thread
is to initiate transfers (with a delay between retry) until the transfer is
succeeded or canceled. Also there is a maximum number of thread that can run
at the same time. For this we have a monitor that enable us to limit the
number of simultaneous download (Monitor.begin() that wait until a slot is
available and Monitor.finish() that release a slot)
So the thread can be in 4 state: tranferring, sleepping (waiting delay),
Waiting for a slot, or doing someting else (initialisation...)
My goal is to be able to cancel the thread in the 4 situation without
blocking and to be sure the process is realy cancelled.
This is the version of my class without the concurency problems solved:
public class XferDownloadThread { //V1
String xferSate = INTERRUPTED;
boolean doCancel;
boolean sleeping;
boolean waitingSlot;
XferClient xferClient = null;
public void run() {
doJobInit;
do {
waitingSlot = true;
Monitor.begin();
waitingSlot = false;
if (doCancel) {
Monitor.finish();
return;
}
//<--------LINE A
xferClient = new XferClient()
xferState = xferClient.doTransfer();
Monitor.finish();
if (xferState == INTERRUPTED) {
sleepping = true;
sleep(delayTime);
sleeping = false;
}
} while (xferState == INTERRUPTED)
}
public void cancelXfer() {
doCancel = true;
xferSate = CANCELED;
if (sleeping || waitingSlot)
interrupt();
if (xferClient != null)
xferClient.cancel();
}
}
The first obvious problem is that if I try to cancel the xfer while the
thread is at line A, the transfer will be done anyway.
I solved it like this:
public class XferDownloadThread { //V2
String xferSate = INTERRUPTED;
boolean doCancel;
boolean sleeping;
boolean waitingSlot;
XferClient xferClient;
Object mutexXferClient = new Object();
public void run() {
doJobInit;
do {
waitingSlot = true;
Monitor.begin();
waitingSlot = false;
syncronized (mutexXferClient) {
if (doCancel) {
Monitor.finish();
return;
}
xferClient = new XferClient()
}
xferState = xferClient.doTransfer();
Monitor.finish();
if (xferState == INTERRUPTED) {
sleepping = true;
//<--------LINE B
sleep(delayTime);
//<--------LINEC
sleeping = false;
}
} while (xferState == INTERRUPTED)
}
public void cancelXfer() {
syncronized(mutexXferClient) {
doCancel = true;
xferSate = CANCELED;
if (sleeping || waitingSlot)
interrupt();
if (xferClient != null)
xferClient.cancel();
}
}
}
The second problem is of the same type at line B and C, if I try to cancel
the xfer while the thread is at this line, the interrupt statement will have
no effect and I will go inside the sleep statement anyway.
*********
I need to be sure that the thread is sleeping before calling interrupt() and
I want to be sure that if cancelXfer() has been called I wil not go to
sleep.
*********
I tried to solve it with the same design but it doesn't do the job (the
first case works because the call to the XferClient contructor will not
block, not like sleep and Monitor.begin()).
Let say that the run method acquire the mutexSleeping first, the
cancelXfer() call will block until the sleep() is over because we wait for
the mutexSleeping to be released and it will be released only at the end of
the sleep time. I don't want this to happen since I want the thread to be
canceled immediatly.
I don't know how to handle the problem.
The same design flaw will occur for line E and F and the Monitor.begin()
statement; I want to be sure that if I called cancelXfer() I will not try to
acquire a monitor slot.
I know that these problems may never occur, but I can't leave it like this.
If anybody have a solution to my problem thanks in advance...
public class XferDownloadThread { //V3
String xferSate = INTERRUPTED;
boolean doCancel;
boolean sleeping;
XferClient xferClient;
Object mutexXferClient = new Object();
Object mutexSleeping = new Object();
public void run() {
doJobInit;
do {
waitingSlot = true;
//<---------LINE E
Monitor.begin();
//<---------LINE F
waitingSlot = false;
syncronized (mutexXferClient) {
if (doCancel) {
Monitor.finish();
return;
}
xferClient = new XferClient()
}
xferState = xferClient.doTransfer();
Monitor.finish();
if (xferState == INTERRUPTED) {
syncronized (mutexSleeping) {
if (doCancel)
return;
sleeping = true;
sleep(delayTime);
sleeping = false;
}
}
} while (xferState == INTERRUPTED)
}
public void cancelXfer() {
syncronized(mutexSleeping) {
syncronized(mutexXferClient) {
xferSate = CANCELED;
doCancel = true;
if (sleeping)
interrupt();
if (xferClient != null)
xferClient.cancel();
}
}
}
Olivier