View Javadoc
1   //******************************************************************************
2   //
3   // File:    SharedBooleanArray.java
4   // Package: edu.rit.pj.reduction
5   // Unit:    Class edu.rit.pj.reduction.SharedBooleanArray
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.AtomicIntegerArray;
43  
44  /**
45   * Class SharedBooleanArray provides an array reduction variable with elements
46   * of type <code>boolean</code>.
47   * <P>
48   * Class SharedBooleanArray is multiple thread safe. The methods use lock-free
49   * atomic compare-and-set.
50   * <P>
51   * <I>Note:</I> Class SharedBooleanArray is implemented using class
52   * java.util.concurrent.atomic.AtomicIntegerArray. Each Boolean array element is
53   * stored as an <code>int</code> whose values are restricted to the range of type
54   * <code>boolean</code> (0 = <code>false</code>, 1 = <code>true</code>).
55   *
56   * @author Alan Kaminsky
57   * @version 07-Jun-2007
58   */
59  public class SharedBooleanArray {
60  
61  // Hidden data members.
62      private AtomicIntegerArray myArray;
63  
64  // Exported constructors.
65      /**
66       * Construct a new Boolean array reduction variable with the given length.
67       * Each array element is initially <code>false</code>.
68       *
69       * @param len Length.
70       * @exception NegativeArraySizeException (unchecked exception) Thrown if
71       * <code>len</code> &lt; 0.
72       */
73      public SharedBooleanArray(int len) {
74          myArray = new AtomicIntegerArray(len);
75      }
76  
77      /**
78       * Construct a new Boolean array reduction variable whose elements are
79       * copied from the given array.
80       *
81       * @param array Array to copy.
82       * @exception NullPointerException (unchecked exception) Thrown if
83       * <code>array</code> is null.
84       */
85      public SharedBooleanArray(boolean[] array) {
86          int n = array.length;
87          int[] intarray = new int[n];
88          for (int i = 0; i < n; ++i) {
89              intarray[i] = array[i] ? 1 : 0;
90          }
91          myArray = new AtomicIntegerArray(intarray);
92      }
93  
94  // Exported operations.
95      /**
96       * Returns this array reduction variable's length.
97       *
98       * @return Length.
99       */
100     public int length() {
101         return myArray.length();
102     }
103 
104     /**
105      * Returns this array reduction variable's current value at the given index.
106      *
107      * @param i Index.
108      * @return Current value.
109      */
110     public boolean get(int i) {
111         return myArray.get(i) != 0;
112     }
113 
114     /**
115      * Set this array reduction variable at the given index to the given value.
116      *
117      * @param i Index.
118      * @param value New value.
119      */
120     public void set(int i,
121             boolean value) {
122         myArray.set(i, value ? 1 : 0);
123     }
124 
125     /**
126      * Set this array reduction variable at the given index to the given value
127      * and return the previous value.
128      *
129      * @param i Index.
130      * @param value New value.
131      * @return Previous value.
132      */
133     public boolean getAndSet(int i,
134             boolean value) {
135         return myArray.getAndSet(i, value ? 1 : 0) != 0;
136     }
137 
138     /**
139      * Atomically set this array reduction variable at the given index to the
140      * given updated value if the current value equals the expected value.
141      *
142      * @param i Index.
143      * @param expect Expected value.
144      * @param update Updated value.
145      * @return True if the update happened, false otherwise.
146      */
147     public boolean compareAndSet(int i,
148             boolean expect,
149             boolean update) {
150         return myArray.compareAndSet(i, expect ? 1 : 0, update ? 1 : 0);
151     }
152 
153     /**
154      * Atomically set this array reduction variable at the given index to the
155      * given updated value if the current value equals the expected value. May
156      * fail spuriously.
157      *
158      * @param i Index.
159      * @param expect Expected value.
160      * @param update Updated value.
161      * @return True if the update happened, false otherwise.
162      */
163     @SuppressWarnings("deprecation")
164     public boolean weakCompareAndSet(int i,
165             boolean expect,
166             boolean update) {
167         return myArray.weakCompareAndSet(i, expect ? 1 : 0, update ? 1 : 0);
168     }
169 
170     /**
171      * Combine this array reduction variable at the given index with the given
172      * value using the given operation. (This array <code>[i]</code>) is set to
173      * (this array <code>[i]</code>) <I>op</I> (<code>value</code>), then (this array
174      * <code>[i]</code>) is returned.
175      *
176      * @param i Index.
177      * @param value Value.
178      * @param op Binary operation.
179      * @return (This array <code>[i]</code>) <I>op</I> (<code>value</code>).
180      */
181     public boolean reduce(int i,
182             boolean value,
183             BooleanOp op) {
184         for (;;) {
185             int oldvalue = myArray.get(i);
186             int newvalue = op.op(oldvalue != 0, value) ? 1 : 0;
187             if (myArray.compareAndSet(i, oldvalue, newvalue)) {
188                 return newvalue != 0;
189             }
190         }
191     }
192 
193     /**
194      * Combine this array reduction variable with the given array using the
195      * given operation. For each index <code>i</code> from 0 to this array's
196      * length-1, (this array <code>[i]</code>) is set to (this array <code>[i]</code>)
197      * <I>op</I> (<code>src[i]</code>).
198      * <P>
199      * The <code>reduce()</code> method is multiple thread safe <I>on a per-element
200      * basis.</I> Each individual array element is updated atomically, but the
201      * array as a whole is not updated atomically.
202      *
203      * @param src Source array.
204      * @param op Binary operation.
205      * @exception NullPointerException (unchecked exception) Thrown if
206      * <code>src</code> is null. Thrown if
207      * <code>op</code> is null.
208      * @exception IndexOutOfBoundsException (unchecked exception) Thrown if any
209      * array index would be out of bounds.
210      */
211     public void reduce(boolean[] src,
212             BooleanOp op) {
213         reduce(0, src, 0, myArray.length(), op);
214     }
215 
216     /**
217      * Combine a portion of this array reduction variable with a portion of the
218      * given array using the given operation. For each index <code>i</code> from 0
219      * to <code>len</code>-1, (this array <code>[dstoff+i]</code>) is set to (this array
220      * <code>[dstoff+i]</code>) <I>op</I> (<code>src[srcoff+i]</code>).
221      * <P>
222      * The <code>reduce()</code> method is multiple thread safe <I>on a per-element
223      * basis.</I> Each individual array element is updated atomically, but the
224      * array as a whole is not updated atomically.
225      *
226      * @param dstoff Index of first element to update in this array.
227      * @param src Source array.
228      * @param srcoff Index of first element to update from in the source array.
229      * @param len Number of array elements to update.
230      * @param op Binary operation.
231      * @exception NullPointerException (unchecked exception) Thrown if
232      * <code>src</code> is null. Thrown if
233      * <code>op</code> is null.
234      * @exception IndexOutOfBoundsException (unchecked exception) Thrown if
235      * <code>len</code> &lt; 0. Thrown if any array index would be out of bounds.
236      */
237     public void reduce(int dstoff,
238             boolean[] src,
239             int srcoff,
240             int len,
241             BooleanOp op) {
242         if (len < 0
243                 || dstoff < 0 || dstoff + len > myArray.length()
244                 || srcoff < 0 || srcoff + len > src.length) {
245             throw new IndexOutOfBoundsException();
246         }
247         while (len > 0) {
248             updateLoop:
249             for (;;) {
250                 int oldvalue = myArray.get(dstoff);
251                 int newvalue = op.op(oldvalue != 0, src[srcoff]) ? 1 : 0;
252                 if (myArray.compareAndSet(dstoff, oldvalue, newvalue)) {
253                     break updateLoop;
254                 }
255             }
256             ++dstoff;
257             ++srcoff;
258             --len;
259         }
260     }
261 
262     /**
263      * Returns a string version of this array reduction variable.
264      *
265      * @return String version.
266      */
267     public String toString() {
268         return myArray.toString();
269     }
270 
271 }