1

I try to implement a client-server software in Java RMI to solve the dining philosophers problem (https://en.wikipedia.org/wiki/Dining_philosophers_problem) as part of my studies.

The network has to be able to recognize clients that accidentally disconnected (f. e. crashed) and recover its state. Currently my server application keeps track of all clients in the network (registering new clients, resetting the other clients to distribute the chairs) but not their states.

Therefore I want to use a proactive system where as soon as one of the clients can't connect to another client, it will use a RMI function on the server to remove the client (first deleting it from the ArrayList on the server, afterwards removing it completely by resetting all clients):


Snippet from Server.java

@Override
public synchronized boolean deleteClient(String IP) throws RemoteException, ServerNotActiveException {
    if(clients.contains(IP)) {  
        log.log(Level.FINE, "Remove inactive client {0} from ArrayList...", IP);
        clients.remove(IP);
        return true;
    }
    return false;
}

@Override
public void removeClient(String IP) throws RemoteException, ServerNotActiveException {
    log.log(Level.FINE, "Removing inactive client {0} from the system...", IP);
    resetClientsForRemoval();
}

Snippet from Client.java

catch (ConnectException e) {
    log.log(Level.SEVERE, "Client seems to be down\n", e);
    if (server.deleteClient(IP)) {
        new Thread(new Runnable() {
            public void run() {
                try {
                    server.removeClient(IP);
                } catch (RemoteException e) {
                    log.log(Level.SEVERE, "Error during removal.\n", e);
                } catch (ServerNotActiveException e) {
                    log.log(Level.SEVERE, "Error during removal.\n", e);
                }
            }
        }).start();
    }
}

This means I first check if I can delete the client from the ArrayList (or did someone else already remove it) and afterwards execute the final removal of the client by resetting all clients in the network.

But now I have a problem. The code snippet for Client.java is used by several functions that Threads from a class Philosopher.java call (f. e. during the acquisition of a fork or chair on a remote client). To reset all clients I first stop all threads in Client.java and join them:


Snippet from Philosopher.java to stop the thread (using while(running) loop in run()

public void terminate() {
    running = false;
}

Snippet from Client.java to stop/join the threads

@Override
public void stopClient() throws RemoteException, ServerNotActiveException {
    for (int i = 0; i < threads.size(); i++) {
        log.log( Level.FINE, "{0} temporarily leaving the monastery.", philosophers.get(i).toString());
        try {
            philosophers.get(i).terminate();
            threads.get(i).join();
        } catch (InterruptedException e) {
            log.log(Level.SEVERE, "Couldn't join thread!\n{0}", e);
        }
    }
    log.log( Level.FINE, "Client stopped.");
}

But it seems like I can't join the thread that is calling the resetClientsForRemoval in the inner Thread class.


My Question:

Is there a different way to call the removal functions to completely separate them from the calling thread? Else it would be a cyclic lock because I try to join a thread by calling the join function inside a function that this thread is executing.

Thanks in advance for all your help!

Cheers,

Stefan


reset function from Client.java if needed

@Override
public void resetClient(int numberOfChairs, String[] neighbors) throws RemoteException, ServerNotActiveException {
    chairs = new Semaphore [numberOfChairs]; 
    for (int i = 0; i < chairs.length; i++) {
        chairs[i] = new Semaphore(1);
    }
    //generate local forks
    forks = new Semaphore [numberOfChairs];
    for (int i = 0; i < forks.length; i++) {
        forks[i] = new Semaphore(1);
    }
    this.neighbors = neighbors;
    threads = new ArrayList<Thread>();
    for (int i = 0; i < philosophers.size(); i++)
        threads.add(new Thread(philosophers.get(philosophers.size() - 1)));
    int i = 0;
    for (Thread t : threads) {
        log.log(Level.FINE,"{0} entering the updated monastery.", philosophers.get(i).toString());
        t.start();
        i++;
    }
}
Community
  • 1
  • 1
  • 1
    Haven't read your entire question, but if you do `new Thread().start()` it will be completely independent from the thread that started it. – aioobe Dec 13 '15 at 17:55
  • @aioobe Ok, even if this thread calls Thread.join on the creating "parent" Thread? Will this join wait for the execution of the newly created thread or will it just join its normal routine, that it enters after creating the new thread? I thought that there is a cyclic lock because of the new thread calling join on its parent thread and the parent thread waiting for the new thread to finish its job. – HibikiTaisuna Dec 13 '15 at 18:00
  • Letting a client remove a user from your server seems like a major hacking vulnerablitity – ControlAltDel Dec 13 '15 at 18:17
  • @ControlAltDel Yes, it definitely is. But fortunately we don't have to care about security of this network. Therefore this dirty solution is sufficient. But I definitely would rather delete it on my server (without polling). – HibikiTaisuna Dec 13 '15 at 18:58
  • If thread A calls `join` on thread B, then thread A will wait for B to terminate. (The call to `join` will block until B has finished it's execution.) – aioobe Dec 13 '15 at 19:23
  • 'Thread inside another thread' is meaningless. All threads except the first are started by another thread. There is nothing new in what you're asking there. If you want threads to be independent, don't use `join()`. You haven't explained what on earth is the point of calling `removeClient()` in a separate thread, and your question from then on is incomprehensible. – user207421 Dec 13 '15 at 19:40
  • @EJP my reason to call removeClient() in a separate thread was necessary because removeClient() would join the thread that called this function and join waits for the thread to finish its job => waiting until it joined itself (which doesn't work). My method to call removeClient() was actually correct, but the way I stopped the Threads wasn't. Simply setting the boolean for running (while(running)) to false wasn't enough to stop every Thread in this scenario (I honestly don't know why). I had to call thread.interrupt() before joining it. Now the code works as intended. – HibikiTaisuna Dec 16 '15 at 15:10

1 Answers1

0

My method to call removeClient() in a separate Thread was actually correct, but the way I stopped the Threads wasn't. Simply setting the boolean for running (while(running)) to false wasn't enough to stop every Thread in this scenario (I honestly don't know why). I had to call thread.interrupt() before calling join. Now the code works as intended => a Thread started in another Thread doesn't block the successful execution of join in the "parent" Thread.