1 //******************************************************************************
2 //
3 // File: SharedLongArray.java
4 // Package: edu.rit.pj.reduction
5 // Unit: Class edu.rit.pj.reduction.SharedLongArray
6 //
7 // This Java source file is copyright (C) 2007 by Alan Kaminsky. All rights
8 // reserved. For further information, contact the author, Alan Kaminsky, at
9 // ark@cs.rit.edu.
10 //
11 // This Java source file is part of the Parallel Java Library ("PJ"). PJ is free
12 // software; you can redistribute it and/or modify it under the terms of the GNU
13 // General Public License as published by the Free Software Foundation; either
14 // version 3 of the License, or (at your option) any later version.
15 //
16 // PJ is distributed in the hope that it will be useful, but WITHOUT ANY
17 // WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
18 // A PARTICULAR PURPOSE. See the GNU General Public License for more details.
19 //
20 // Linking this library statically or dynamically with other modules is making a
21 // combined work based on this library. Thus, the terms and conditions of the GNU
22 // General Public License cover the whole combination.
23 //
24 // As a special exception, the copyright holders of this library give you
25 // permission to link this library with independent modules to produce an
26 // executable, regardless of the license terms of these independent modules, and
27 // to copy and distribute the resulting executable under terms of your choice,
28 // provided that you also meet, for each linked independent module, the terms
29 // and conditions of the license of that module. An independent module is a module
30 // which is not derived from or based on this library. If you modify this library,
31 // you may extend this exception to your version of the library, but you are not
32 // obligated to do so. If you do not wish to do so, delete this exception
33 // statement from your version.
34 //
35 // A copy of the GNU General Public License is provided in the file gpl.txt. You
36 // may also obtain a copy of the GNU General Public License on the World Wide
37 // Web at http://www.gnu.org/licenses/gpl.html.
38 //
39 //******************************************************************************
40 package edu.rit.pj.reduction;
41
42 import java.util.concurrent.atomic.AtomicLongArray;
43
44 /**
45 * Class SharedLongArray provides an array reduction variable with elements of
46 * type <code>long</code>.
47 * <P>
48 * Class SharedLongArray is multiple thread safe. The methods use lock-free
49 * atomic compare-and-set.
50 * <P>
51 * <I>Note:</I> Class SharedLongArray is implemented using class
52 * java.util.concurrent.atomic.AtomicLongArray.
53 *
54 * @author Alan Kaminsky
55 * @version 24-Aug-2007
56 */
57 public class SharedLongArray {
58
59 // Hidden data members.
60 private AtomicLongArray myArray;
61
62 // Exported constructors.
63 /**
64 * Construct a new long array reduction variable with the given length. Each
65 * array element is initially 0.
66 *
67 * @param len Length.
68 * @exception NegativeArraySizeException (unchecked exception) Thrown if
69 * <code>len</code> < 0.
70 */
71 public SharedLongArray(int len) {
72 myArray = new AtomicLongArray(len);
73 }
74
75 /**
76 * Construct a new long array reduction variable whose elements are copied
77 * from the given array.
78 *
79 * @param array Array to copy.
80 * @exception NullPointerException (unchecked exception) Thrown if
81 * <code>array</code> is null.
82 */
83 public SharedLongArray(long[] array) {
84 myArray = new AtomicLongArray(array);
85 }
86
87 // Exported operations.
88 /**
89 * Returns this array reduction variable's length.
90 *
91 * @return Length.
92 */
93 public int length() {
94 return myArray.length();
95 }
96
97 /**
98 * Returns this array reduction variable's current value at the given index.
99 *
100 * @param i Index.
101 * @return Current value.
102 */
103 public long get(int i) {
104 return myArray.get(i);
105 }
106
107 /**
108 * Set this array reduction variable at the given index to the given value.
109 *
110 * @param i Index.
111 * @param value New value.
112 */
113 public void set(int i,
114 long value) {
115 myArray.set(i, value);
116 }
117
118 /**
119 * Set this array reduction variable at the given index to the given value
120 * and return the previous value.
121 *
122 * @param i Index.
123 * @param value New value.
124 * @return Previous value.
125 */
126 public long getAndSet(int i,
127 long value) {
128 return myArray.getAndSet(i, value);
129 }
130
131 /**
132 * Atomically set this array reduction variable at the given index to the
133 * given updated value if the current value equals the expected value.
134 *
135 * @param i Index.
136 * @param expect Expected value.
137 * @param update Updated value.
138 * @return True if the update happened, false otherwise.
139 */
140 public boolean compareAndSet(int i,
141 long expect,
142 long update) {
143 return myArray.compareAndSet(i, expect, update);
144 }
145
146 /**
147 * Atomically set this array reduction variable at the given index to the
148 * given updated value if the current value equals the expected value. May
149 * fail spuriously.
150 *
151 * @param i Index.
152 * @param expect Expected value.
153 * @param update Updated value.
154 * @return True if the update happened, false otherwise.
155 */
156 @SuppressWarnings("deprecation")
157 public boolean weakCompareAndSet(int i,
158 long expect,
159 long update) {
160 return myArray.weakCompareAndSet(i, expect, update);
161 }
162
163 /**
164 * Add one to this array reduction variable at the given index and return
165 * the previous value.
166 *
167 * @param i Index.
168 * @return Previous value.
169 */
170 public long getAndIncrement(int i) {
171 return myArray.getAndIncrement(i);
172 }
173
174 /**
175 * Subtract one from this array reduction variable at the given index and
176 * return the previous value.
177 *
178 * @param i Index.
179 * @return Previous value.
180 */
181 public long getAndDecrement(int i) {
182 return myArray.getAndDecrement(i);
183 }
184
185 /**
186 * Add the given value to this array reduction variable at the given index
187 * and return the previous value.
188 *
189 * @param i Index.
190 * @param value Value to add.
191 * @return Previous value.
192 */
193 public long getAndAdd(int i,
194 long value) {
195 return myArray.getAndAdd(i, value);
196 }
197
198 /**
199 * Add one to this array reduction variable at the given index and return
200 * the new value.
201 *
202 * @param i Index.
203 * @return New value.
204 */
205 public long incrementAndGet(int i) {
206 return myArray.incrementAndGet(i);
207 }
208
209 /**
210 * Subtract one from this array reduction variable at the given index and
211 * return the new value.
212 *
213 * @param i Index.
214 * @return New value.
215 */
216 public long decrementAndGet(int i) {
217 return myArray.decrementAndGet(i);
218 }
219
220 /**
221 * Add the given value to this array reduction variable at the given index
222 * and return the new value.
223 *
224 * @param i Index.
225 * @param value Value to add.
226 * @return New value.
227 */
228 public long addAndGet(int i,
229 long value) {
230 return myArray.addAndGet(i, value);
231 }
232
233 /**
234 * Combine this array reduction variable at the given index with the given
235 * value using the given operation. (This array <code>[i]</code>) is set to
236 * (this array <code>[i]</code>) <I>op</I> (<code>value</code>), then (this array
237 * <code>[i]</code>) is returned.
238 *
239 * @param i Index.
240 * @param value Value.
241 * @param op Binary operation.
242 * @return (This array <code>[i]</code>) <I>op</I> (<code>value</code>).
243 */
244 public long reduce(int i,
245 long value,
246 LongOp op) {
247 for (;;) {
248 long oldvalue = myArray.get(i);
249 long newvalue = op.op(oldvalue, value);
250 if (myArray.compareAndSet(i, oldvalue, newvalue)) {
251 return newvalue;
252 }
253 }
254 }
255
256 /**
257 * Combine this array reduction variable with the given array using the
258 * given operation. For each index <code>i</code> from 0 to this array's
259 * length-1, (this array <code>[i]</code>) is set to (this array <code>[i]</code>)
260 * <I>op</I> (<code>src[i]</code>).
261 * <P>
262 * The <code>reduce()</code> method is multiple thread safe <I>on a per-element
263 * basis.</I> Each individual array element is updated atomically, but the
264 * array as a whole is not updated atomically.
265 *
266 * @param src Source array.
267 * @param op Binary operation.
268 * @exception NullPointerException (unchecked exception) Thrown if
269 * <code>src</code> is null. Thrown if
270 * <code>op</code> is null.
271 * @exception IndexOutOfBoundsException (unchecked exception) Thrown if any
272 * array index would be out of bounds.
273 */
274 public void reduce(long[] src,
275 LongOp op) {
276 reduce(0, src, 0, myArray.length(), op);
277 }
278
279 /**
280 * Combine a portion of this array reduction variable with a portion of the
281 * given array using the given operation. For each index <code>i</code> from 0
282 * to <code>len</code>-1, (this array <code>[dstoff+i]</code>) is set to (this array
283 * <code>[dstoff+i]</code>) <I>op</I> (<code>src[srcoff+i]</code>).
284 * <P>
285 * The <code>reduce()</code> method is multiple thread safe <I>on a per-element
286 * basis.</I> Each individual array element is updated atomically, but the
287 * array as a whole is not updated atomically.
288 *
289 * @param dstoff Index of first element to update in this array.
290 * @param src Source array.
291 * @param srcoff Index of first element to update from in the source array.
292 * @param len Number of array elements to update.
293 * @param op Binary operation.
294 * @exception NullPointerException (unchecked exception) Thrown if
295 * <code>src</code> is null. Thrown if
296 * <code>op</code> is null.
297 * @exception IndexOutOfBoundsException (unchecked exception) Thrown if
298 * <code>len</code> < 0. Thrown if any array index would be out of bounds.
299 */
300 public void reduce(int dstoff,
301 long[] src,
302 int srcoff,
303 int len,
304 LongOp op) {
305 if (len < 0
306 || dstoff < 0 || dstoff + len > myArray.length()
307 || srcoff < 0 || srcoff + len > src.length) {
308 throw new IndexOutOfBoundsException();
309 }
310 while (len > 0) {
311 updateLoop:
312 for (;;) {
313 long oldvalue = myArray.get(dstoff);
314 long newvalue = op.op(oldvalue, src[srcoff]);
315 if (myArray.compareAndSet(dstoff, oldvalue, newvalue)) {
316 break updateLoop;
317 }
318 }
319 ++dstoff;
320 ++srcoff;
321 --len;
322 }
323 }
324
325 /**
326 * Returns a string version of this array reduction variable.
327 *
328 * @return String version.
329 */
330 public String toString() {
331 return myArray.toString();
332 }
333
334 }