1 //****************************************************************************** 2 // 3 // File: ParallelIteration.java 4 // Package: edu.rit.pj 5 // Unit: Class edu.rit.pj.ParallelIteration 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; 41 42 /** 43 * Class ParallelIteration is the abstract base class for a parallel iteration 44 * that is executed inside a {@linkplain ParallelRegion}. The parallel iteration 45 * lets you iterate over a group of items, with a separate parallel team thread 46 * processing each item. The generic type parameter T specifies the items' data 47 * type. The items can be the elements of an array, the items obtained from an 48 * {@linkplain java.util.Iterator Iterator}, or the items contained in an 49 * {@linkplain java.lang.Iterable Iterable} collection. 50 * <P> 51 * To execute a parallel iteration, create a {@linkplain ParallelRegion} object; 52 * create an instance of a concrete subclass of class ParallelIteration; and 53 * pass this instance to the parallel region's <code>execute()</code> method. Either 54 * every parallel team thread must call the parallel region's <code>execute()</code> 55 * method with identical arguments, or every thread must not call the 56 * <code>execute()</code> method. You can do all this using an anonymous inner 57 * class; for example: 58 * <PRE> 59 * new ParallelRegion() 60 * { 61 * ArrayList<String> list = new ArrayList<String>(); 62 * . . . 63 * public void run() 64 * { 65 * . . . 66 * execute (list, new ParallelIteration<String>() 67 * { 68 * // Thread local variable declarations 69 * . . . 70 * public void start() 71 * { 72 * // Per-thread pre-loop initialization code 73 * . . . 74 * } 75 * public void run (String item) 76 * { 77 * // Loop body code 78 * . . . 79 * } 80 * public void finish() 81 * { 82 * // Per-thread post-loop finalization code 83 * . . . 84 * } 85 * }); 86 * } 87 * . . . 88 * } 89 * </PRE> 90 * <P> 91 * The parallel region's <code>execute()</code> method does the following. One of 92 * the parallel team threads sets up the source of the items to be iterated over 93 * -- either an array's elements, an iterator's items, or an iterable 94 * collection's contents. (Note that only <I>one</I> thread does this setup; but 95 * because all threads must call the parallel region's <code>execute()</code> method 96 * with identical arguments, it doesn't matter which thread does the setup.) 97 * Each parallel team thread calls the parallel iteration's <code>start()</code> 98 * method once before beginning any loop iterations. Each thread repeatedly 99 * calls the parallel iteration's <code>run()</code> method, passing in a different 100 * item on each call, until all the items have been processed. When a thread has 101 * finished calling <code>run()</code>, the thread calls the parallel iteration's 102 * <code>finish()</code> method. Then the thread waits at a barrier. When all the 103 * threads have reached the barrier, the <code>execute()</code> method returns. 104 * <P> 105 * Note that each parallel team thread actually creates its own instance of the 106 * parallel iteration class and passes that instance to the parallel region's 107 * <code>execute()</code> method. Thus, any fields declared in the parallel 108 * iteration class will <I>not</I> be shared by all the threads, but instead 109 * will be private to each thread. 110 * <P> 111 * The <code>start()</code> method is intended for performing per-thread 112 * initialization before starting the loop iterations. If no such initialization 113 * is needed, omit the <code>start()</code> method. 114 * <P> 115 * The <code>run()</code> method contains the code for the loop body. It does 116 * whatever processing is needed on the one item passed in as an argument. Note 117 * that, unlike a parallel for loop (class {@linkplain ParallelForLoop}), a 118 * parallel iteration is not "chunked;" each parallel team thread always 119 * processes just one item at a time. 120 * <P> 121 * The <code>finish()</code> method is intended for performing per-thread 122 * finalization after finishing the loop iterations. If no such finalization is 123 * needed, omit the <code>finish()</code> method. 124 * <P> 125 * Sometimes a portion of a parallel iteration has to be executed sequentially 126 * in the same order as the items' iteration order, while the rest of the 127 * parallel iteration can be executed concurrently. For example, the loop body 128 * is performing some computation that can be executed in parallel for different 129 * items, but the results of each computation must be written to a file 130 * sequentially in the items' iteration order. The <code>ordered()</code> method is 131 * provided for this purpose. A call to the <code>ordered()</code> method may appear 132 * once in the parallel iteration's <code>run()</code> method, like so: 133 * <PRE> 134 * public void run (String item) 135 * { 136 * // This portion executed concurrently 137 * . . . 138 * ordered (new ParallelSection() 139 * { 140 * public void run() 141 * { 142 * // This portion executed sequentially 143 * // in the items' iteration order 144 * . . . 145 * } 146 * }); 147 * // This portion executed concurrently again 148 * . . . 149 * } 150 * </PRE> When called, the <code>ordered()</code> method waits until the 151 * <code>ordered()</code> 152 * method has been called and has returned for all items prior to the current 153 * item. Then the <code>ordered()</code> method calls the given parallel section's 154 * <code>run()</code> method. When the parallel section's <code>run()</code> method 155 * returns, the <code>ordered()</code> method returns. If the parallel section's 156 * <code>run()</code> method throws an exception, the <code>ordered()</code> method 157 * throws that same exception. 158 * <P> 159 * It is possible to stop a parallel iteration using the <code>stopLoop()</code> 160 * method, like this: 161 * <PRE> 162 * public void run (String item) 163 * { 164 * // Loop body 165 * . . . 166 * if (/*time to stop the loop*/) 167 * { 168 * stopLoop(); 169 * return; 170 * } 171 * // More loop body 172 * . . . 173 * } 174 * </PRE> Once <code>stopLoop()</code> is called, after each parallel team thread 175 * finishes processing its current item, each thread will process no further 176 * items and will proceed to finish the parallel iteration. Note well that 177 * stopping a parallel iteration is not the same as executing a <code>break</code> 178 * statement in a regular loop. The parallel iteration does not stop until each 179 * thread, 180 * <I>including the thread that called <code>stopLoop()</code></I>, has finished 181 * processing its current item. Thus, processing may continue for a while after 182 * <code>stopLoop()</code> is called. (The <code>return</code> statement in the above 183 * example causes the thread that called <code>stopLoop()</code> to stop its 184 * processing early.) 185 * <P> 186 * Normally, at the end of the parallel iteration, the parallel team threads 187 * wait for each other at a barrier. To eliminate this barrier wait, include 188 * {@link edu.rit.pj.BarrierAction#NO_WAIT BarrierAction.NO_WAIT} in the <code>execute()</code> 189 * method call: 190 * <PRE> 191 * new ParallelRegion() 192 * { 193 * . . . 194 * public void run() 195 * { 196 * . . . 197 * execute (list, new ParallelIteration<String>() 198 * { 199 * . . . 200 * }, 201 * BarrierAction.NO_WAIT); 202 * . . . 203 * } 204 * } 205 * </PRE> To execute a section of code in a single thread as part of the barrier 206 * synchronization, include an instance of class {@linkplain BarrierAction} in 207 * the <code>execute()</code> method call. The barrier action object's 208 * <code>run()</code> method contains the code to be executed in a single thread 209 * while the other threads wait: 210 * <PRE> 211 * new ParallelRegion() 212 * { 213 * . . . 214 * public void run() 215 * { 216 * . . . 217 * execute (list, new ParallelIteration<String>() 218 * { 219 * . . . 220 * }, 221 * new BarrierAction() 222 * { 223 * public void run() 224 * { 225 * // Single-threaded code goes here 226 * . . . 227 * } 228 * }); 229 * . . . 230 * } 231 * } 232 * </PRE> For further information, see class {@linkplain BarrierAction}. 233 * <P> 234 * If the parallel iteration's <code>start()</code>, <code>run()</code>, or 235 * <code>finish()</code> method throws an exception in one of the threads, then that 236 * thread executes no further code in the loop, and the parallel region's 237 * <code>execute()</code> method throws that same exception in that thread. 238 * Furthermore, the other threads in the parallel team also process no further 239 * items after finishing their current items. Thus, if one thread throws an 240 * exception, the whole parallel iteration exits with some (perhaps none) of the 241 * iterations unperformed. 242 * 243 * @param <T> Data type of the items iterated over. 244 * @author Alan Kaminsky 245 * @version 11-Nov-2007 246 */ 247 public abstract class ParallelIteration<T> 248 extends ParallelConstruct { 249 250 // Hidden data members. 251 // Item generator, used to obtain the items, to break this parallel 252 // iteration, and to implement the ordered() construct. 253 ItemGenerator<T> myItemGenerator; 254 255 // Iteration index for the ordered() construct. 256 int myOrderedIndex; 257 258 // Exported constructors. 259 /** 260 * Construct a new parallel iteration. 261 */ 262 public ParallelIteration() { 263 super(); 264 } 265 266 // Exported operations. 267 /** 268 * Perform per-thread initialization actions before starting the loop 269 * iterations. 270 * <P> 271 * The <code>start()</code> method may be overridden in a subclass. If not 272 * overridden, the <code>start()</code> method does nothing. 273 * 274 * @exception Exception The <code>start()</code> method may throw any exception. 275 * @throws java.lang.Exception if any. 276 */ 277 public void start() 278 throws Exception { 279 } 280 281 /** 282 * Process one item in this parallel iteration. The <code>run()</code> method 283 * must perform the loop body for the given item. 284 * <P> 285 * The <code>run()</code> method must be overridden in a subclass. 286 * 287 * @param item Item. 288 * @exception Exception The <code>run()</code> method may throw any exception. 289 * @throws java.lang.Exception if any. 290 */ 291 public abstract void run(T item) 292 throws Exception; 293 294 /** 295 * Perform per-thread finalization actions after finishing the loop 296 * iterations. 297 * <P> 298 * The <code>finish()</code> method may be overridden in a subclass. If not 299 * overridden, the <code>finish()</code> method does nothing. 300 * 301 * @exception Exception The <code>finish()</code> method may throw any 302 * exception. 303 * @throws java.lang.Exception if any. 304 */ 305 public void finish() 306 throws Exception { 307 } 308 309 /** 310 * Execute the given section of code in the items' iteration order. A call 311 * to the <code>ordered()</code> method may appear in this parallel iteration's 312 * <code>run()</code> method. When called, the <code>ordered()</code> method waits 313 * until the <code>ordered()</code> method has been called and has returned for 314 * all items prior to the current item. Then the <code>ordered()</code> method 315 * calls the <code>run()</code> method of <code>theParallelSection</code>. When the 316 * parallel section's <code>run()</code> method returns, the <code>ordered()</code> 317 * method returns. If the parallel section's <code>run()</code> method throws an 318 * exception, the <code>ordered()</code> method throws that same exception. 319 * <P> 320 * The <code>ordered()</code> method is used when a portion of a parallel 321 * iteration has to be executed sequentially in the items' iteration order, 322 * while the rest of the parallel iteration can be executed concurrently. 323 * <P> 324 * <I>Note:</I> Either the <code>ordered()</code> method must be called exactly 325 * once during each call of the parallel iteration's <code>run()</code> method, 326 * or the <code>ordered()</code> method must not be called at all. 327 * 328 * @param theSection Parallel section to execute in order. 329 * @exception NullPointerException (unchecked exception) Thrown if 330 * <code>theSection</code> is null. 331 * @exception IllegalStateException (unchecked exception) Thrown if no 332 * parallel team is executing this parallel iteration. 333 * @exception Exception Thrown if <code>theSection</code>'s <code>run()</code> 334 * method throws an exception. 335 * @throws java.lang.Exception if any. 336 */ 337 public final void ordered(ParallelSection theSection) 338 throws Exception { 339 // Verify preconditions. 340 if (theSection == null) { 341 throw new IllegalStateException("ParallelIteration.ordered(): Parallel section is null"); 342 } 343 if (myTeam == null) { 344 throw new IllegalStateException("ParallelIteration.ordered(): No parallel team executing"); 345 } 346 347 // Wait until the ordered() construct has finished for all previous 348 // iterations. 349 if (myItemGenerator.myOrderedIndex != this.myOrderedIndex) { 350 Spinner spinner = new Spinner(); 351 while (myItemGenerator.myOrderedIndex != this.myOrderedIndex) { 352 spinner.spin(); 353 } 354 } 355 356 // Execute parallel section. Propagate any exception. 357 theSection.myTeam = this.myTeam; 358 try { 359 theSection.run(); 360 } finally { 361 theSection.myTeam = null; 362 363 // Notify that the ordered construct has finished for this 364 // iteration. 365 ++this.myOrderedIndex; 366 myItemGenerator.myOrderedIndex = this.myOrderedIndex; 367 } 368 } 369 370 /** 371 * Stop this parallel iteration. Once <code>stopLoop()</code> is called, after 372 * each parallel team thread finishes processing its current item, each 373 * thread will process no further items and will proceed to finish this 374 * parallel iteration. 375 * 376 * @exception IllegalStateException (unchecked exception) Thrown if no 377 * parallel team is executing this parallel iteration. 378 */ 379 public final void stopLoop() { 380 if (myTeam == null) { 381 throw new IllegalStateException("ParallelIteration.stopLoop(): No parallel team executing"); 382 } 383 myItemGenerator.myBreak = true; 384 } 385 386 // Hidden operations. 387 /** 388 * Execute one chunk of iterations of this parallel for loop. This method 389 * performs common processing, then calls the <code>run()</code> method. 390 * 391 * @param index Iteration index. 392 * @param item Item. 393 * 394 * @exception Exception This method may throw any exception. 395 */ 396 void commonRun(int index, 397 T item) 398 throws Exception { 399 myOrderedIndex = index; 400 run(item); 401 } 402 403 }