Synchronisation problem

Discussion in 'Java' started by Olivier Merigon, Jul 28, 2004.

  1. 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
     
    Olivier Merigon, Jul 28, 2004
    #1
    1. Advertising

  2. Olivier Merigon

    David Hilsee Guest

    "Olivier Merigon" <_N0SP@> wrote in message
    news:ce8h5f$28t$...
    > 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.

    --
    David Hilsee
     
    David Hilsee, Jul 29, 2004
    #2
    1. Advertising

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

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Ram
    Replies:
    1
    Views:
    606
    Mike Treseler
    Feb 24, 2005
  2. Glenn

    Session End Synchronisation

    Glenn, Oct 31, 2003, in forum: ASP .Net
    Replies:
    1
    Views:
    406
    Nicole Calinoiu
    Oct 31, 2003
  3. Thor
    Replies:
    1
    Views:
    1,044
    Mikkel Heisterberg
    Jul 2, 2003
  4. tom fredriksen

    synchronisation problem

    tom fredriksen, Mar 21, 2006, in forum: Java
    Replies:
    4
    Views:
    442
    Carl Burke
    Mar 29, 2006
  5. CG
    Replies:
    1
    Views:
    138
    Nicolai Admiraal
    Oct 26, 2004
Loading...

Share This Page