views:

77

answers:

4

i'm trying to build a semi file sharing program, when each computer acts both as a server and as a client.

I give multiple threads the option to DL the file from my system.

also, i've got a user interface that can recieve a delete message.

my problem is that i want that the minute a delete message receieved, i wait for all the threads that are DL the file to finish DL, and ONLY than excute file.delete(). what is the best way to do it?

I thought about some database that holds > and iterate and check if the thread is active, but it seems clumsy. is there a better way? thanks

+2  A: 

I think you can do this more simply than using a database. I would put a thin wrapper class around File.. a TrackedFile. It has the file inside, and a count of how many people are reading it. When you do to delete, just stop allowing new people to grab the file, and wait for the count to get to 0.

Since you are dealing with many threads accessing shared state, make sure you properly use java.util.concurrent

bwawok
+1  A: 

I am not sure this addresses all your problems, but this is what I have in mind:

Assumming that all read/write/delete operations occur only from within the same application, a thread synchronization mechanism using locks can be useful.

For every new file that arrives, a new read/write lock can be created (See Java's ReentrantReadWriteLock). The read lock should be acquired for all read operations, while the write lock should be acquired for write/delete operations. Of course, when the lock is acquired you should check whether the operation is still meaningful (i.e. whether the file still exists).

Eyal Schneider
I like it. When a single process manages the file, `ReentrantReadWriteLock` is a much simpler solution than trying to use another tool like a database or filesystem lock to synchronize.
erickson
A: 

Your delete event handling thread (probably your UI) will become un-responsive if you have to wait for all readers to finish. Instead queue the delete and periodically poll for deletions which can be processed. You can use:

private class DeleteRunnable implements Runnable {
 public void run() {
  while (!done) {
   ArrayList<DeletedObject> tmpList = null;
   synchronized (masterList) {
    tmpList = new ArrayList<DeletedObjects>(masterList);
   }

   for (DeletedObject o : tmpList)
    if (o.waitForReaders(500, TimeUnit.MilliSeconds))
     synchronized (masterList) {
      masterList.remove(o);
     }
  }
 }
}  
Justin
A: 

If you were to restructure your design just slightly so that loading the file from disk and uploading the file to the client were not done in the same thread, you could wait for the file to stop being accessed simply by locking out new threads from reading this file, then iterating over all of the threads reading from that file and do a join() on each one, one at a time. As long as the file-reading threads terminate directly after loading the file, the iteration will finish the moment the last thread is no longer reading the file and you are good to go.

The following paragraph is based on the assumption that you keep re-reading the file data over multiple times, even if the reading threads are both reading during the same general time frame, since that's what it sounds like you're doing.

Doing it this way, separating file-reading into separate threads, would also allow you to have a single thread loading a specific file and to have multiple client-uploads getting the data from the single reading pass over the file. There are several optimizations you could implement with this, depending on what type of project this is for. If you do, make sure you don't keep too much file data in memory, or the obvious will happen. But if you are guaranteed by the nature of your project that there will be few and/or small files that will not take up too much memory, this is a great side effect of separating file-loading into a separate thread.

If you go this route of using join(), you could use the join(milliseconds) variant if you want the deletion thread to be able to wait a certain period then demand the other threads stop (for huge files and/or times when many files are being accessed so HD is going slow), if they haven't already. Just get a timestamp of (now + theDurationYouWantToWait) and join(impatientTimestamp-currentTimestamp), and send an interrupt to all file-loading threads in the middle of the loop on if(currentTimestamp >= impatientTimestamp) - then have the file-loading threads check for it in the loop where they're reading file data, then re-join() the thread that the join(milliseconds) aborted from and continue the join()ing iteration you were doing.

Loduwijk