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 }