View Javadoc
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> &lt; 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> &lt; 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 }