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 }