Synchronisation problem

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
 
D

David Hilsee

Olivier Merigon said:
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.

I found your post a little confusing. I'm not even sure what you mean by
being "able to cancel the thread in the 4 situation without blocking and to
be sure the process is realy cancelled." From your code, it seems like you
understand multithreading but are confusing yourself somehow. The code you
posted had multiple objects as locks, multiple synchronized blocks, and
multiple boolean flags, and I was reminded of the times when I thought too
hard about multithreading and turned my code into a giant, unnecessary mess.

Usually, when one thread wishes to tell another thread that it must
terminate, it sets a flag that lets the thread know that it should
terminate, and that thread later inspects the value of that flag and
terminates. If, after setting the flag, the first thread wishes to wait
until the second thread has finished terminating, it should call
Thread.join().

Most of the time, the "boolean flag" strategy works. If the second thread
wishes to occasionally pause, then there are two options: Thread.sleep() or
Object.wait(). Either will work. The "boolean flag" strategy can be
transformed into a strategy that works with pausing as well. Hopefully the
following example code will illustrate my point.

public class TerminationFlag {
private boolean flag = false;

// Returns true if the flag has been set to true.
public synchronized boolean isSet(){
return flag;
}

// Blocks the current thread until either this flag is set or the
timeout
// (in milliseconds) expires. A timeout of zero means that this method
// will wait forever (effectively, no timeout).
// If this method returns false, then this flag was not set (the timeout
// expired).
// If this method returns true, then this flag was set before the
timeout
// expired.
// If this method throws InterruptedException, then interrupt() was
called
// while the current thread was waiting for this flag to be set.
public synchronized boolean pause( long timeout )
throws InterruptedException {
wait( timeout );
return flag;
}

// Sets the flag, which tells the second thread to terminate.
public synchronized void set(){
flag = true;
notifyAll();
}
}

The above is not the only solution, and it's not necessarily the best
solution. It is just an example that I thought might help you come to grips
with your current problem. In the above code, it is not necessary for one
to call Thread.interrupt() as long as only one thread calls pause(), and
that may simplify things for you. It's possible to use Thread.interrupt()
as well, but it seems that you are having trouble with it, so I'm offerring
a (potentially) simpler alternative.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,769
Messages
2,569,576
Members
45,054
Latest member
LucyCarper

Latest Threads

Top