summaryrefslogtreecommitdiff
path: root/java/src/RWMutex.java
blob: f3970690c4e809dc5f158c9d2c204a78c7a0ed18 (plain)
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
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
/*************************************************
 *
 * = PACKAGE
 *    ACE.Concurrency
 *
 * = FILENAME
 *    RWMutex.java
 *
 *@author Ross Dargahi (rossd@krinfo.com), Prashant Jain, and Irfan Pyarali
 *
 *************************************************/

package ACE.Concurrency;

import ACE.OS.*;

/*******************************************************************************
* <HR>
* <B> Description </B>
* <BR>
* This class increments a read/write lock. A read/write lock allows multiple
* readers or a single writer to access the guarded element.
* This implementation is based on the C++ version of ACE.
* </PRE><P><HR>
* <B> Notes </B>
* <UL>
* <LI> This class does not support recursive semantics
* </UL>
*******************************************************************************/
public class RWMutex
{
  /**
   * Acquires the write lock
   * @exception InterruptedException Lock acquisition interrupted
   **/
  public void acquire()
    throws InterruptedException
  {
    acquireWrite();
  }

  /**
   * Acquires the read lock
   * @exception InterruptedException Lock acquisition interrupted
   **/
  public void acquireRead()
    throws InterruptedException
  {
    // make sure we start with no exception
    InterruptedException exception_ = null;
    
    // grab lock
    lock_.acquire ();
    
    // Give preference to writers who are waiting.
    while (referenceCount_ < 0 || numberOfWaitingWriters_ > 0)
      {
	numberOfWaitingReaders_++;
	try 
	  {
	    waitingReaders_.Wait ();
	  }
	catch (InterruptedException exception)
	  {
	    // cache exception
	    exception_ = exception;
	  }
	numberOfWaitingReaders_--;
      }
    
    if (exception_ == null)
      // No errors
      referenceCount_++;

    // make sure this is released in all cases
    lock_.release ();

    if (exception_ != null)
      // error: propogate
      throw exception_;
  }
  
  /**
   * Acquires the write lock
   * @exception InterruptedException Lock acquisition interrupted
   **/
  public void acquireWrite()
    throws InterruptedException
  {
    // make sure we start with no exception
    InterruptedException exception_ = null;
    
    // grab lock
    lock_.acquire ();
    
    // Give preference to writers who are waiting.
    while (referenceCount_ != 0)
      {
	numberOfWaitingWriters_++;
	try 
	  {
	    waitingWriters_.Wait ();
	  }
	catch (InterruptedException exception)
	  {
	    // cache exception
	    exception_ = exception;
	  }
	numberOfWaitingWriters_--;
      }
    
    if (exception_ == null)
      // No errors
      referenceCount_ = -1;

    // make sure this is released in all cases
    lock_.release ();

    if (exception_ != null)
      // error: propogate
      throw exception_;
  }

  /**
   * Release held lock
   * @exception InterruptedException Lock acquisition interrupted
   **/
  public void release()
    throws InterruptedException
  {
    lock_.acquire ();
    
    // Releasing a reader.
    if (referenceCount_ > 0) 
      referenceCount_--;
    else 
      // Releasing a writer.
      if (referenceCount_ == -1) 
	referenceCount_ = 0;
    
    // Give preference to writers over readers...
    if (numberOfWaitingWriters_ > 0)
      {
	waitingWriters_.signal ();
      }
    else if (numberOfWaitingReaders_ > 0)
      {
	waitingReaders_.broadcast ();
      }
	
    
    lock_.release ();
  }

  private Mutex lock_ = new Mutex (); 
  // Serialize access to internal state.
 
  private Condition waitingReaders_ = new Condition (lock_);
  // Reader threads waiting to acquire the lock.
 
  private int numberOfWaitingReaders_;
  // Number of waiting readers.
 
  private Condition waitingWriters_ = new Condition (lock_);
  // Writer threads waiting to acquire the lock.
 
  private int numberOfWaitingWriters_ = 0;
  // Number of waiting writers.
 
  private int referenceCount_ = 0;
  // Value is -1 if writer has the lock, else this keeps track of the
  // number of readers holding the lock.
}