View Javadoc
1   //******************************************************************************
2   //
3   // File:    ParallelTeamThread.java
4   // Package: edu.rit.pj
5   // Unit:    Class edu.rit.pj.ParallelTeamThread
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  
41  //******************************************************************************
42  // File modified 10/8/2014 by Jacob Litman to enable garbage collection of
43  // ParallelTeamThreads.
44  //******************************************************************************
45  package edu.rit.pj;
46  
47  import java.util.concurrent.Semaphore;
48  
49  /**
50   * Class ParallelTeamThread provides one thread in a {@linkplain ParallelTeam}
51   * of threads for executing a {@linkplain ParallelRegion} in parallel.
52   *
53   * @author Alan Kaminsky
54   * @version 20-Dec-2007
55   */
56  class ParallelTeamThread
57          extends Thread {
58  
59  // Hidden data members.
60      // Reference to the parallel team.
61      ParallelTeam myTeam;
62  
63      // Index of this thread within the parallel team.
64      int myIndex;
65  
66      // Semaphore for synchronizing threads at the beginning of a parallel
67      // region.
68      Semaphore myRegionBeginSemaphore = new Semaphore(0);
69  
70      // Thread barrier flag. Used by the ParallelRegion.barrier() method.
71      volatile int myBarrierFlag;
72  
73      // Parallel construct counter. Counts how many times this thread has arrived
74      // at the top of a parallel construct.
75      volatile int myConstructCount;
76  
77      // IntegerSchedule object for a parallel for loop.
78      volatile IntegerSchedule myIntegerSchedule;
79  
80      // LongSchedule object for a parallel for loop.
81      volatile LongSchedule myLongSchedule;
82  
83      // Item generator object for a parallel iteration.
84      volatile ItemGenerator<?> myItemGenerator;
85  
86      // Exception thrown while setting up a parallel construct, or null if none.
87      volatile Throwable myConstructException;
88  
89      // 128 bytes of extra padding to avert cache interference.
90      private long p0, p1, p2, p3, p4, p5, p6, p7;
91      private long p8, p9, pa, pb, pc, pd, pe, pf;
92  
93  // Exported constructors.
94      /**
95       * Construct a new parallel team thread.
96       *
97       * @param theTeam Parallel team to which this thread belongs.
98       * @param theIndex Index of this thread within the team.
99       */
100     public ParallelTeamThread(ParallelTeam theTeam,
101             int theIndex) {
102         myTeam = theTeam;
103         myIndex = theIndex;
104         setDaemon(true);
105         start();
106     }
107 
108 // Exported operations.
109     /**
110      * Run this parallel team thread.
111      */
112     public void run() {
113         for (;;) {
114             // Wait until released by the main thread.
115             myRegionBeginSemaphore.acquireUninterruptibly();
116 
117             if (myTeam.myRegion instanceof KillRegion) {
118                 try {
119                     myTeam.myRegion.run();
120                 } catch (Exception ex) {
121                     System.err.printf("Error exiting parallel team thread: %s%n", ex);
122                 }
123                 break;
124             }
125             
126             // Call the parallel region's run() method. Save any
127             // exception for later.
128             try {
129                 myTeam.myRegion.run();
130             } catch (Throwable exc) {
131                 synchronized (System.err) {
132                     System.err.println("Parallel team thread " + myIndex
133                             + ": ParallelRegion.run() threw an exception");
134                     exc.printStackTrace(System.err);
135                     if (exc.getCause() != null) {
136                         exc.getCause().printStackTrace(System.err);
137                     }
138                 }
139                 myTeam.myExceptionMap.put(myIndex, exc);
140             }
141 
142             // Tell the main thread we're done.
143             myTeam.myRegionEndSemaphore.release();
144         }
145         myTeam.myRegionEndSemaphore.release();
146     }
147 
148 // Hidden operations.
149     /**
150      * Do this thread's portion of a barrier with no barrier action. This method
151      * is called by thread 1 through thread K-1 of the parallel team.
152      */
153     void barrier() {
154         // Get the new team barrier flag.
155         int newBarrierFlag = myTeam.myBarrierFlag ^ 1;
156 
157         // Switch this thread to the new barrier flag.
158         myBarrierFlag = newBarrierFlag;
159 
160         // Wait until thread 0 has switched to the new team barrier flag.
161         if (myTeam.myBarrierFlag != newBarrierFlag) {
162             Spinner spinner = new Spinner();
163             while (myTeam.myBarrierFlag != newBarrierFlag) {
164                 spinner.spin();
165             }
166         }
167     }
168 
169     /**
170      * Do this thread's portion of a barrier with a barrier action. This method
171      * is called by thread 1 through thread K-1 of the parallel team.
172      *
173      * @param action Barrier action.
174      *
175      * @exception Exception Thrown if the <code>action</code>'s <code>run()</code>
176      * method throws an exception.
177      */
178     void barrier(BarrierAction action)
179             throws Exception {
180         barrier();
181     }
182 
183     /**
184      * Do processing when this thread arrives at the top of a parallel
185      * construct.
186      *
187      * @return True if this thread is the first to arrive, false otherwise.
188      */
189     boolean arriveAtParallelConstruct() {
190         // Wait until every thread's construct count is greater than or equal to
191         // this thread's construct count.
192         int K = myTeam.K;
193         for (int i = 0; i < K; ++i) {
194             ParallelTeamThread thread_i = myTeam.myThread[i];
195             if (thread_i.myConstructCount < this.myConstructCount) {
196                 Spinner spinner = new Spinner();
197                 while (thread_i.myConstructCount < this.myConstructCount) {
198                     spinner.spin();
199                 }
200             }
201         }
202 
203         // Determine if this thread is the first to arrive.
204         for (;;) {
205             int oldConstructCount = myTeam.myConstructCount.get();
206             if (oldConstructCount != myConstructCount) {
207                 // This thread is not the first to arrive.
208                 myConstructCount = oldConstructCount;
209                 return false;
210             }
211             // This thread may be the first to arrive.
212             if (myTeam.myConstructCount.compareAndSet(oldConstructCount, oldConstructCount + 1)) {
213                 // This thread is the first to arrive.
214                 myConstructCount = oldConstructCount + 1;
215                 return true;
216             }
217         }
218     }
219 
220     /**
221      * Set this thread's IntegerSchedule.
222      *
223      * @param theSchedule Integer schedule.
224      */
225     void setIntegerSchedule(IntegerSchedule theSchedule) {
226         // Wait until myIntegerSchedule is null.
227         if (myIntegerSchedule != null) {
228             Spinner spinner = new Spinner();
229             while (myIntegerSchedule != null) {
230                 spinner.spin();
231             }
232         }
233 
234         myIntegerSchedule = theSchedule;
235     }
236 
237     /**
238      * Get this thread's IntegerSchedule.
239      *
240      * @return IntegerSchedule.
241      *
242      * @exception Exception This method can throw any exception.
243      */
244     IntegerSchedule getIntegerSchedule()
245             throws Exception {
246         // Wait until myIntegerSchedule or myConstructException is set to a
247         // non-null value.
248         if (myIntegerSchedule == null && myConstructException == null) {
249             Spinner spinner = new Spinner();
250             while (myIntegerSchedule == null && myConstructException == null) {
251                 spinner.spin();
252             }
253         }
254 
255         // Make temporary copies and null out originals.
256         IntegerSchedule schedule = myIntegerSchedule;
257         myIntegerSchedule = null;
258         Throwable exc = myConstructException;
259         myConstructException = null;
260 
261         // Re-throw exception if necessary.
262         ParallelTeam.rethrow(exc);
263 
264         return schedule;
265     }
266 
267     /**
268      * Set this thread's LongSchedule.
269      *
270      * @param theSchedule Long schedule.
271      */
272     void setLongSchedule(LongSchedule theSchedule) {
273         // Wait until myLongSchedule is null.
274         if (myLongSchedule != null) {
275             Spinner spinner = new Spinner();
276             while (myLongSchedule != null) {
277                 spinner.spin();
278             }
279         }
280 
281         myLongSchedule = theSchedule;
282     }
283 
284     /**
285      * Get this thread's LongSchedule.
286      *
287      * @return LongSchedule.
288      *
289      * @exception Exception This method can throw any exception.
290      */
291     LongSchedule getLongSchedule()
292             throws Exception {
293         // Wait until myLongSchedule or myConstructException is set to a
294         // non-null value.
295         if (myLongSchedule == null && myConstructException == null) {
296             Spinner spinner = new Spinner();
297             while (myLongSchedule == null && myConstructException == null) {
298                 spinner.spin();
299             }
300         }
301 
302         // Make temporary copies and null out originals.
303         LongSchedule schedule = myLongSchedule;
304         myLongSchedule = null;
305         Throwable exc = myConstructException;
306         myConstructException = null;
307 
308         // Re-throw exception if necessary.
309         ParallelTeam.rethrow(exc);
310 
311         return schedule;
312     }
313 
314     /**
315      * Set this thread's ItemGenerator.
316      *
317      * @param theItemGenerator Item generator.
318      */
319     void setItemGenerator(ItemGenerator<?> theItemGenerator) {
320         // Wait until myItemGenerator is null.
321         if (myItemGenerator != null) {
322             Spinner spinner = new Spinner();
323             while (myItemGenerator != null) {
324                 spinner.spin();
325             }
326         }
327 
328         myItemGenerator = theItemGenerator;
329     }
330 
331     /**
332      * Get this thread's ItemGenerator.
333      *
334      * @return Item generator.
335      *
336      * @exception Exception This method can throw any exception.
337      */
338     ItemGenerator<?> getItemGenerator()
339             throws Exception {
340         // Wait until myItemGenerator or myConstructException is set to a
341         // non-null value.
342         if (myItemGenerator == null && myConstructException == null) {
343             Spinner spinner = new Spinner();
344             while (myItemGenerator == null && myConstructException == null) {
345                 spinner.spin();
346             }
347         }
348 
349         // Make temporary copies and null out originals.
350         ItemGenerator<?> generator = myItemGenerator;
351         myItemGenerator = null;
352         Throwable exc = myConstructException;
353         myConstructException = null;
354 
355         // Re-throw exception if necessary.
356         ParallelTeam.rethrow(exc);
357 
358         return generator;
359     }
360 
361     /**
362      * Set this thread's construct exception.
363      *
364      * @param theException Construct exception.
365      */
366     void setConstructException(Throwable theException) {
367         // Wait until myConstructException is null.
368         if (myConstructException != null) {
369             Spinner spinner = new Spinner();
370             while (myConstructException != null) {
371                 spinner.spin();
372             }
373         }
374 
375         myConstructException = theException;
376     }
377 
378 }