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