-
Notifications
You must be signed in to change notification settings - Fork 0
/
Mutex.java
112 lines (101 loc) · 5.68 KB
/
Mutex.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
package org.rosuda.JRI;
/** This class implements a (not so) simple mutex. The initial state of the mutex is unlocked. */
public class Mutex {
public static boolean verbose=false;
/** defines the current mutex state */
private boolean locked=false;
/** thread that locked this mutex (used for simple deadlock-detection) */
private Thread lockedBy=null;
/** locks the mutex. If the mutex is already locked, waits until the mutex becomes free. Make sure the same thread doesn't issue two locks, because that will cause a deadlock. Use {@link #safeLock()} instead if you wish to detect such deadlocks. */
public synchronized void lock()
{
while (locked) {
if (lockedBy==Thread.currentThread())
System.err.println("FATAL ERROR: org.rosuda.JRI.Mutex detected a deadlock! The application is likely to hang indefinitely!");
if (verbose)
System.out.println("INFO: "+toString()+" is locked by "+lockedBy+", but "+Thread.currentThread()+" waits for release (no timeout)");
try {
wait();
} catch (InterruptedException e) {
if (verbose)
System.out.println("INFO: "+toString()+" caught InterruptedException");
}
}
locked=true;
lockedBy=Thread.currentThread();
if (verbose) System.out.println("INFO: "+toString()+" locked by "+lockedBy);
}
/** locks the mutex. If the mutex is already locked, waits until the mutex becomes free. Make sure the same thread doesn't issue two locks, because that will cause a deadlock.
@param to timeout in milliseconds, see {@link #wait()}.
@return <code>true</code> if the lock was successful, <code>false</code> if not
*/
public synchronized boolean lockWithTimeout(long to)
{
if (locked) {
if (lockedBy==Thread.currentThread())
System.err.println("FATAL ERROR: org.rosuda.JRI.Mutex detected a deadlock! The application is likely to hang indefinitely!");
if (verbose)
System.out.println("INFO: "+toString()+" is locked by "+lockedBy+", but "+Thread.currentThread()+" waits for release (timeout "+to+" ms)");
try {
wait(to);
} catch (InterruptedException e) {
if (verbose)
System.out.println("INFO: "+toString()+" caught InterruptedException");
}
}
if (!locked) {
locked=true;
lockedBy=Thread.currentThread();
if (verbose) System.out.println("INFO: "+toString()+" locked by "+lockedBy);
return true;
}
if (verbose) System.out.println("INFO: "+toString()+" timeout, failed to obtain lock for "+Thread.currentThread());
return false;
}
/** attempts to lock the mutex and returns information about its success.
@return 0 if the mutex was locked sucessfully<br>1 if the mutex is already locked by another thread<br>-1 is the mutex is already locked by the same thread (hence a call to {@link #lock()} would cause a deadlock). */
public synchronized int tryLock()
{
if (verbose) System.out.println("INFO: "+toString()+" tryLock by "+Thread.currentThread());
if (locked) return (lockedBy==Thread.currentThread())?-1:1;
locked=true;
lockedBy=Thread.currentThread();
if (verbose) System.out.println("INFO: "+toString()+" locked by "+lockedBy);
return 0;
}
/** Locks the mutex. It works like {@link #lock()} except that it returns immediately if the same thread already owns the lock. It is safer to use this function rather than {@link #lock()}, because lock can possibly cause a deadlock which won't be resolved.
@return <code>true</code> is the mutex was successfully locked, <code>false</code> if deadlock was detected (i.e. the same thread has already the lock). */
public synchronized boolean safeLock()
{
if (locked && lockedBy==Thread.currentThread()) {
if (verbose) System.out.println("INFO: "+toString()+" unable to provide safe lock for "+Thread.currentThread());
return false;
}
lock();
return true;
}
/** Locks the mutex. It works like {@link #lockWithTimeout(long)} except that it returns immediately if the same thread already owns the lock. It is safer to use this function rather than {@link #lockWithTimeout(long)}, because lock can possibly cause a deadlock which won't be resolved.
@return <code>true</code> is the mutex was successfully locked, <code>false</code> if deadlock was detected or timeout elapsed. */
public synchronized boolean safeLockWithTimeout(long to)
{
if (locked && lockedBy==Thread.currentThread()) {
if (verbose) System.out.println("INFO: "+toString()+" unable to provide safe lock (deadlock detected) for "+Thread.currentThread());
return false;
}
return lockWithTimeout(to);
}
/** unlocks the mutex. It is possible to unlock an unlocked mutex, but a warning may be issued. */
public synchronized void unlock()
{
if (locked && lockedBy!=Thread.currentThread())
System.err.println("WARNING: org.rosuda.JRI.Mutex was unlocked by other thread than locked! This may soon lead to a crash...");
locked=false;
if (verbose) System.out.println("INFO: "+toString()+" unlocked by "+Thread.currentThread());
// notify just 1 in case more of them are waiting
notify();
}
public String toString()
{
return super.toString()+"["+((locked)?"":"un")+"locked"+((!locked)?"":(", by "+((lockedBy==Thread.currentThread())?"current":"another")+" thread"))+"]";
}
}