1 //****************************************************************************** 2 // 3 // File: SharedFloatArray.java 4 // Package: edu.rit.pj.reduction 5 // Unit: Class edu.rit.pj.reduction.SharedFloatArray 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 SharedFloatArray provides an array reduction variable with elements of 46 * type <code>float</code>. 47 * <P> 48 * Class SharedFloatArray is multiple thread safe. The methods use lock-free 49 * atomic compare-and-set. 50 * <P> 51 * <I>Note:</I> Class SharedFloatArray is implemented using class 52 * java.util.concurrent.atomic.AtomicIntegerArray. Each float array element is 53 * stored as an <code>int</code> whose bit pattern is the same as the float value. 54 * 55 * @author Alan Kaminsky 56 * @version 24-Aug-2007 57 */ 58 public class SharedFloatArray { 59 60 // Hidden data members. 61 private AtomicIntegerArray myArray; 62 63 // Exported constructors. 64 /** 65 * Construct a new float array reduction variable with the given length. 66 * Each array element is initially 0. 67 * 68 * @param len Length. 69 * @exception NegativeArraySizeException (unchecked exception) Thrown if 70 * <code>len</code> < 0. 71 */ 72 public SharedFloatArray(int len) { 73 myArray = new AtomicIntegerArray(len); 74 } 75 76 /** 77 * Construct a new float array reduction variable whose elements are copied 78 * from the given array. 79 * 80 * @param array Array to copy. 81 * @exception NullPointerException (unchecked exception) Thrown if 82 * <code>array</code> is null. 83 */ 84 public SharedFloatArray(float[] array) { 85 int n = array.length; 86 int[] intarray = new int[n]; 87 for (int i = 0; i < n; ++i) { 88 intarray[i] = Float.floatToIntBits(array[i]); 89 } 90 myArray = new AtomicIntegerArray(intarray); 91 } 92 93 // Exported operations. 94 /** 95 * Returns this array reduction variable's length. 96 * 97 * @return Length. 98 */ 99 public int length() { 100 return myArray.length(); 101 } 102 103 /** 104 * Returns this array reduction variable's current value at the given index. 105 * 106 * @param i Index. 107 * @return Current value. 108 */ 109 public float get(int i) { 110 return Float.intBitsToFloat(myArray.get(i)); 111 } 112 113 /** 114 * Set this array reduction variable at the given index to the given value. 115 * 116 * @param i Index. 117 * @param value New value. 118 */ 119 public void set(int i, 120 float value) { 121 myArray.set(i, Float.floatToIntBits(value)); 122 } 123 124 /** 125 * Set this array reduction variable at the given index to the given value 126 * and return the previous value. 127 * 128 * @param i Index. 129 * @param value New value. 130 * @return Previous value. 131 */ 132 public float getAndSet(int i, 133 float value) { 134 return Float.intBitsToFloat(myArray.getAndSet(i, Float.floatToIntBits(value))); 135 } 136 137 /** 138 * Atomically set this array reduction variable at the given index to the 139 * given updated value if the current value equals the expected value. 140 * 141 * @param i Index. 142 * @param expect Expected value. 143 * @param update Updated value. 144 * @return True if the update happened, false otherwise. 145 */ 146 public boolean compareAndSet(int i, 147 float expect, 148 float update) { 149 return myArray.compareAndSet(i, Float.floatToIntBits(expect), Float.floatToIntBits(update)); 150 } 151 152 /** 153 * Atomically set this array reduction variable at the given index to the 154 * given updated value if the current value equals the expected value. May 155 * fail spuriously. 156 * 157 * @param i Index. 158 * @param expect Expected value. 159 * @param update Updated value. 160 * @return True if the update happened, false otherwise. 161 */ 162 @SuppressWarnings("deprecation") 163 public boolean weakCompareAndSet(int i, 164 float expect, 165 float update) { 166 return myArray.weakCompareAndSet(i, Float.floatToIntBits(expect), Float.floatToIntBits(update)); 167 } 168 169 /** 170 * Add one to this array reduction variable at the given index and return 171 * the previous value. 172 * 173 * @param i Index. 174 * @return Previous value. 175 */ 176 public float getAndIncrement(int i) { 177 for (;;) { 178 int oldvalueInt = myArray.get(i); 179 float oldvalue = Float.intBitsToFloat(oldvalueInt); 180 float newvalue = oldvalue + 1.0f; 181 int newvalueInt = Float.floatToIntBits(newvalue); 182 if (myArray.compareAndSet(i, oldvalueInt, newvalueInt)) { 183 return oldvalue; 184 } 185 } 186 } 187 188 /** 189 * Subtract one from this array reduction variable at the given index and 190 * return the previous value. 191 * 192 * @param i Index. 193 * @return Previous value. 194 */ 195 public float getAndDecrement(int i) { 196 for (;;) { 197 int oldvalueInt = myArray.get(i); 198 float oldvalue = Float.intBitsToFloat(oldvalueInt); 199 float newvalue = oldvalue - 1.0f; 200 int newvalueInt = Float.floatToIntBits(newvalue); 201 if (myArray.compareAndSet(i, oldvalueInt, newvalueInt)) { 202 return oldvalue; 203 } 204 } 205 } 206 207 /** 208 * Add the given value to this array reduction variable at the given index 209 * and return the previous value. 210 * 211 * @param i Index. 212 * @param value Value to add. 213 * @return Previous value. 214 */ 215 public float getAndAdd(int i, 216 float value) { 217 for (;;) { 218 int oldvalueInt = myArray.get(i); 219 float oldvalue = Float.intBitsToFloat(oldvalueInt); 220 float newvalue = oldvalue + value; 221 int newvalueInt = Float.floatToIntBits(newvalue); 222 if (myArray.compareAndSet(i, oldvalueInt, newvalueInt)) { 223 return oldvalue; 224 } 225 } 226 } 227 228 /** 229 * Add one to this array reduction variable at the given index and return 230 * the new value. 231 * 232 * @param i Index. 233 * @return New value. 234 */ 235 public float incrementAndGet(int i) { 236 for (;;) { 237 int oldvalueInt = myArray.get(i); 238 float oldvalue = Float.intBitsToFloat(oldvalueInt); 239 float newvalue = oldvalue + 1.0f; 240 int newvalueInt = Float.floatToIntBits(newvalue); 241 if (myArray.compareAndSet(i, oldvalueInt, newvalueInt)) { 242 return newvalue; 243 } 244 } 245 } 246 247 /** 248 * Subtract one from this array reduction variable at the given index and 249 * return the new value. 250 * 251 * @param i Index. 252 * @return New value. 253 */ 254 public float decrementAndGet(int i) { 255 for (;;) { 256 int oldvalueInt = myArray.get(i); 257 float oldvalue = Float.intBitsToFloat(oldvalueInt); 258 float newvalue = oldvalue - 1.0f; 259 int newvalueInt = Float.floatToIntBits(newvalue); 260 if (myArray.compareAndSet(i, oldvalueInt, newvalueInt)) { 261 return newvalue; 262 } 263 } 264 } 265 266 /** 267 * Add the given value to this array reduction variable at the given index 268 * and return the new value. 269 * 270 * @param i Index. 271 * @param value Value to add. 272 * @return New value. 273 */ 274 public float addAndGet(int i, 275 float value) { 276 for (;;) { 277 int oldvalueInt = myArray.get(i); 278 float oldvalue = Float.intBitsToFloat(oldvalueInt); 279 float newvalue = oldvalue + value; 280 int newvalueInt = Float.floatToIntBits(newvalue); 281 if (myArray.compareAndSet(i, oldvalueInt, newvalueInt)) { 282 return newvalue; 283 } 284 } 285 } 286 287 /** 288 * Combine this array reduction variable at the given index with the given 289 * value using the given operation. (This array <code>[i]</code>) is set to 290 * (this array <code>[i]</code>) <I>op</I> (<code>value</code>), then (this array 291 * <code>[i]</code>) is returned. 292 * 293 * @param i Index. 294 * @param value Value. 295 * @param op Binary operation. 296 * @return (This array <code>[i]</code>) <I>op</I> (<code>value</code>). 297 */ 298 public float reduce(int i, 299 float value, 300 FloatOp op) { 301 for (;;) { 302 int oldvalueInt = myArray.get(i); 303 float oldvalue = Float.intBitsToFloat(oldvalueInt); 304 float newvalue = op.op(oldvalue, value); 305 int newvalueInt = Float.floatToIntBits(newvalue); 306 if (myArray.compareAndSet(i, oldvalueInt, newvalueInt)) { 307 return newvalue; 308 } 309 } 310 } 311 312 /** 313 * Combine this array reduction variable with the given array using the 314 * given operation. For each index <code>i</code> from 0 to this array's 315 * length-1, (this array <code>[i]</code>) is set to (this array <code>[i]</code>) 316 * <I>op</I> (<code>src[i]</code>). 317 * <P> 318 * The <code>reduce()</code> method is multiple thread safe <I>on a per-element 319 * basis.</I> Each individual array element is updated atomically, but the 320 * array as a whole is not updated atomically. 321 * 322 * @param src Source array. 323 * @param op Binary operation. 324 * @exception NullPointerException (unchecked exception) Thrown if 325 * <code>src</code> is null. Thrown if 326 * <code>op</code> is null. 327 * @exception IndexOutOfBoundsException (unchecked exception) Thrown if any 328 * array index would be out of bounds. 329 */ 330 public void reduce(float[] src, 331 FloatOp op) { 332 reduce(0, src, 0, myArray.length(), op); 333 } 334 335 /** 336 * Combine a portion of this array reduction variable with a portion of the 337 * given array using the given operation. For each index <code>i</code> from 0 338 * to <code>len</code>-1, (this array <code>[dstoff+i]</code>) is set to (this array 339 * <code>[dstoff+i]</code>) <I>op</I> (<code>src[srcoff+i]</code>). 340 * <P> 341 * The <code>reduce()</code> method is multiple thread safe <I>on a per-element 342 * basis.</I> Each individual array element is updated atomically, but the 343 * array as a whole is not updated atomically. 344 * 345 * @param dstoff Index of first element to update in this array. 346 * @param src Source array. 347 * @param srcoff Index of first element to update from in the source array. 348 * @param len Number of array elements to update. 349 * @param op Binary operation. 350 * @exception NullPointerException (unchecked exception) Thrown if 351 * <code>src</code> is null. Thrown if 352 * <code>op</code> is null. 353 * @exception IndexOutOfBoundsException (unchecked exception) Thrown if 354 * <code>len</code> < 0. Thrown if any array index would be out of bounds. 355 */ 356 public void reduce(int dstoff, 357 float[] src, 358 int srcoff, 359 int len, 360 FloatOp op) { 361 if (len < 0 362 || dstoff < 0 || dstoff + len > myArray.length() 363 || srcoff < 0 || srcoff + len > src.length) { 364 throw new IndexOutOfBoundsException(); 365 } 366 while (len > 0) { 367 updateLoop: 368 for (;;) { 369 int oldvalueInt = myArray.get(dstoff); 370 float oldvalue = Float.intBitsToFloat(oldvalueInt); 371 float newvalue = op.op(oldvalue, src[srcoff]); 372 int newvalueInt = Float.floatToIntBits(newvalue); 373 if (myArray.compareAndSet(dstoff, oldvalueInt, newvalueInt)) { 374 break updateLoop; 375 } 376 } 377 ++dstoff; 378 ++srcoff; 379 --len; 380 } 381 } 382 383 /** 384 * Returns a string version of this array reduction variable. 385 * 386 * @return String version. 387 */ 388 public String toString() { 389 StringBuilder b = new StringBuilder(); 390 b.append('['); 391 int n = myArray.length(); 392 for (int i = 0; i < n; ++i) { 393 if (i > 0) { 394 b.append(", "); 395 } 396 b.append(get(i)); 397 } 398 b.append(']'); 399 return b.toString(); 400 } 401 402 }