Locking files on unix problem

Hi, I'm trying to lock a text file for exclusive write use for different threads of an application, started from websphere.

I wrote a small standalone test harnass to verify the solution, and found that it works just fine on windows, but completely fails under unix !

Using java 1.4.2_08 (business requirement).

just 2 files: one to start up x number of threads, and the other one locks and unlocks. This is the code:

== frun.java ===

class frun{

publicstaticvoid main(String[] argv){

for(int n = 0; n < 5; n++){

System.out.println("Starting thread: "+ n);

new cFile(n).start();

}

}

}

== cFile.java ===

import java.util.*;

import java.lang.*;

import java.io.*;

import java.nio.*;

import java.nio.channels.*;

class cFileextends Thread{

int nr;

public cFile(int n){

nr=n;

}

publicvoid run(){

FileLock lock;

try{

System.out.println("Thread "+nr+" running");

RandomAccessFile raf=new RandomAccessFile("lock.lock","rw");

FileChannel ch=raf.getChannel();

lock =ch.lock();

System.out.println(nr+" Lock="+lock.toString());

try{

sleep(100);

}catch( InterruptedException ie){}

lock.release();

System.out.println("Thread "+nr+" stopped");

}catch (IOException io){

System.out.println("file not accessible");

}

}

}

the output on windows is, as expected:

C:\java\lt2>\j2sdk1.4.2_08\bin\java frun

Starting thread: 0

Starting thread: 1

Starting thread: 2

Thread 1 running

1 Lock=sun.nio.ch.FileLockImpl[0:9223372036854775807 exclusive valid]

Thread 0 running

Thread 2 running

Starting thread: 3

Starting thread: 4

Thread 3 running

Thread 4 running

Thread 1 stopped

0 Lock=sun.nio.ch.FileLockImpl[0:9223372036854775807 exclusive valid]

Thread 0 stopped

2 Lock=sun.nio.ch.FileLockImpl[0:9223372036854775807 exclusive valid]

Thread 2 stopped

3 Lock=sun.nio.ch.FileLockImpl[0:9223372036854775807 exclusive valid]

Thread 3 stopped

4 Lock=sun.nio.ch.FileLockImpl[0:9223372036854775807 exclusive valid]

Thread 4 stopped

==============================================

However, on Unix (Sun Sparc, Solaris 5.8) it appears as:

mljm> run

Starting thread: 0

Starting thread: 1

Starting thread: 2

Thread 1 running

Thread 0 running

Starting thread: 3

Starting thread: 4

Thread 2 running

Thread 3 running

Thread 4 running

4 Lock=sun.nio.ch.FileLockImpl[0:9223372036854775807 exclusive valid]

0 Lock=sun.nio.ch.FileLockImpl[0:9223372036854775807 exclusive valid]

3 Lock=sun.nio.ch.FileLockImpl[0:9223372036854775807 exclusive valid]

2 Lock=sun.nio.ch.FileLockImpl[0:9223372036854775807 exclusive valid]

1 Lock=sun.nio.ch.FileLockImpl[0:9223372036854775807 exclusive valid]

Thread 4 stopped

Thread 0 stopped

Thread 3 stopped

Thread 1 stopped

Thread 2 stopped

================================

Which shows that the lock did not work.

What is going on here? Is there a solution?

Thanks

Michael

[4875 byte] By [869836mljmeermana] at [2007-11-26 12:18:45]
# 1
Read the docs for FileLock:File locks are held on behalf of the entire Java virtual machine. They are not suitable for controlling access to a file by multiple threads within the same virtual machine.Message was edited by: davidholmes
39402davidholmesa at 2007-7-7 14:58:54 > top of Java-index,Archived Forums,Socket Programming...
# 2
For threads in the same VM treat the file as any other shared resource and use a lock/semaphore to control access.
39402davidholmesa at 2007-7-7 14:58:54 > top of Java-index,Archived Forums,Socket Programming...
# 3

> For threads in the same VM treat the file as any

> other shared resource and use a lock/semaphore to

> control access.

Hi David, I read and re-read the docs several times, forwards, backwards, before posting my original message. The point is

a) I don't understand the difference well enough between VM and threads within a process

(why VM wide but not between threads?)

c) why does it work on windows. My test environment is on windows, while the production env is on a solaris and on a redHat server

b) no alternative is given in the doc.

I read up on semaphores and don't think it will work in my environment,

because I have no access to the parent process from where the threads are started. The only access I have is to the threads themselves, but even there not the start level.

I may misunderstand, so if you have a code example I could try I would be ever so grateful!

I thought about creating my own lock file: see if a file exists, if not, quickly create it and write a fingerprint to it. Then read it back to make sure it wasn't someone else creating this file at the same time.

Problem is: How to create a unique fingerprint ?

Random is not a help. Two threads that are started up at the same mSec (quite likely in my environment) have a high probability of seeding the random generator with the same number, thus generating the same sequence of 'random' numbers.

Using the process PID, even if they are different for each thread, means using native code, which is a no-go.

A non-interuptable sequence of commands would do the job: check file exists, create file - but I do not know if this is possible in java.

I cannot believe there is no solution to this, surely other programmers must have encountered this problem.

Thnaks

Michael

869836mljmeermana at 2007-7-7 14:58:54 > top of Java-index,Archived Forums,Socket Programming...
# 4

Michael,

File locking API's (fcntl on solaris/linux, LockFileEx on Windows) are based on the process. All threads belong to the same process hence these API's can't be used for protection between threads.

I have no idea why this appeared to work on Windows, it may just have been a fluke of the scheduling. You might try adding a sleep() while you hold the FileLock and see if that allows other threads to also access the file. Or it may be some difference in the Windows file system - I don't know enough about it to really say.

To use a semaphore/lock at any place where you would acquire the FileLock, acquire the semaphore/lock instead.

Hope this helps.

39402davidholmesa at 2007-7-7 14:58:55 > top of Java-index,Archived Forums,Socket Programming...
# 5

David,

Unfortunately, Semaphores are part of Java1.5, and I'm restricted to java 1.4.2, (and that is not going to get changed any time soon).

The little test program above, when you take away the 'release' statement, and run on windows (XP), it blocks, no further processes get through, so it does not appear to be a fluke, but an implementation issue.

However, there is some light, I did some more testing on random, and it looks like Math.Random() does give out a unique random number, even to processes started well witing the same mSec, both on Windows and Solaris.

The Random() method failed in this respect on windows, I guess the time granularity is better on unix.

Thanks anyway

(Still baffled by the lack of a proper solution to a what i thought would be a common problem.)

869836mljmeermana at 2007-7-7 14:58:55 > top of Java-index,Archived Forums,Socket Programming...
# 6

Michael,

There is a backport of java.util.concurrent available for 1.4.2 - don't have the link handy sorry but google will find it.

But you can easily build a simple semaphore using wait/notify. Alternatively you can just synchronize on each File/stream object before using it.

I'm not sure what "common problem" you are actually trying to solve.

39402davidholmesa at 2007-7-7 14:58:55 > top of Java-index,Archived Forums,Socket Programming...
# 7
Why not just use the synchronized keyword on the method where the OutputStream is opened and closed in the method?
891456iandesouzaa at 2007-7-7 14:58:55 > top of Java-index,Archived Forums,Socket Programming...
# 8
For intra VM locking you need to create your own mechaism using the provided critical section stuff. A monitor object per required guarded resource should work as has been suggested by previous posters.
892130georgekwatsona at 2007-7-7 14:58:55 > top of Java-index,Archived Forums,Socket Programming...
# 9

Yes, that's a possibility, but I was thinking of rearranging the code somewhat such as the following:

import java.util.*;

import java.lang.*;

import java.io.*;

import java.nio.*;

import java.nio.channels.*;

class SharedFile {

RandomAccessFile raf;

SharedFile()

{

try {

raf=new RandomAccessFile("lock.lock", "rw");

} catch (IOException io) {

System.out.println("file not accessible");

}

}

synchronized void accessFile(int nr)

{

System.out.println("Thread "+nr+" running");

FileChannel ch=raf.getChannel();

System.out.println(nr+" Lock");

try {

Thread.currentThread().sleep(100);

} catch( InterruptedException ie) {}

System.out.println("Thread "+nr+" stopped");

}

static class cFile extends Thread

{

int nr;

SharedFile sf_;

public cFile(int n, SharedFile sf) {

nr=n;

sf_ = sf;

}

public void run() {

sf_.accessFile(nr);

}

}

public static void main(String[] argv) {

SharedFile sharedFile = new SharedFile();

for(int n = 0; n < 5; n++) {

System.out.println("Starting thread: "+ n);

new cFile(n, sharedFile).start();

}

}

}

Which yields the following:

java SharedFile

Starting thread: 0

Starting thread: 1

Thread 0 running

Starting thread: 2

Starting thread: 3

Starting thread: 4

0 Lock

Thread 0 stopped

Thread 1 running

1 Lock

Thread 1 stopped

Thread 3 running

3 Lock

Thread 3 stopped

Thread 2 running

2 Lock

Thread 2 stopped

Thread 4 running

4 Lock

Thread 4 stopped

891456iandesouzaa at 2007-7-7 14:58:55 > top of Java-index,Archived Forums,Socket Programming...