ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/jsr166/jsr166/src/test/tck/RecursiveActionTest.java
Revision: 1.13
Committed: Sat Sep 11 07:31:52 2010 UTC (13 years, 8 months ago) by jsr166
Branch: MAIN
Changes since 1.12: +1 -2 lines
Log Message:
whitespace

File Contents

# Content
1 /*
2 * Written by Doug Lea with assistance from members of JCP JSR-166
3 * Expert Group and released to the public domain, as explained at
4 * http://creativecommons.org/licenses/publicdomain
5 */
6 import junit.framework.*;
7 import java.util.concurrent.*;
8 import java.util.*;
9
10
11 public class RecursiveActionTest extends JSR166TestCase {
12
13 public static void main(String[] args) {
14 junit.textui.TestRunner.run(suite());
15 }
16
17 public static Test suite() {
18 return new TestSuite(RecursiveActionTest.class);
19 }
20
21 static final ForkJoinPool mainPool = new ForkJoinPool();
22 static final ForkJoinPool singletonPool = new ForkJoinPool(1);
23 static final ForkJoinPool asyncSingletonPool =
24 new ForkJoinPool(1, ForkJoinPool.defaultForkJoinWorkerThreadFactory,
25 null, true);
26
27 static final class FJException extends RuntimeException {
28 FJException() { super(); }
29 }
30
31 // A simple recursive action for testing
32 static final class FibAction extends RecursiveAction {
33 final int number;
34 int result;
35 FibAction(int n) { number = n; }
36 public void compute() {
37 int n = number;
38 if (n <= 1)
39 result = n;
40 else {
41 FibAction f1 = new FibAction(n - 1);
42 FibAction f2 = new FibAction(n - 2);
43 invokeAll(f1, f2);
44 result = f1.result + f2.result;
45 }
46 }
47 }
48
49 // A recursive action failing in base case
50 static final class FailingFibAction extends RecursiveAction {
51 final int number;
52 int result;
53 FailingFibAction(int n) { number = n; }
54 public void compute() {
55 int n = number;
56 if (n <= 1)
57 throw new FJException();
58 else {
59 FailingFibAction f1 = new FailingFibAction(n - 1);
60 FailingFibAction f2 = new FailingFibAction(n - 2);
61 invokeAll(f1, f2);
62 result = f1.result + f2.result;
63 }
64 }
65 }
66
67 /**
68 * invoke returns when task completes normally.
69 * isCompletedAbnormally and isCancelled return false for normally
70 * completed tasks. getRawResult of a RecursiveAction returns null;
71 */
72 public void testInvoke() {
73 RecursiveAction a = new RecursiveAction() {
74 public void compute() {
75 FibAction f = new FibAction(8);
76 f.invoke();
77 threadAssertTrue(f.result == 21);
78 threadAssertTrue(f.isDone());
79 threadAssertFalse(f.isCancelled());
80 threadAssertFalse(f.isCompletedAbnormally());
81 threadAssertTrue(f.getRawResult() == null);
82 }};
83 mainPool.invoke(a);
84 }
85
86 /**
87 * quietlyInvoke task returns when task completes normally.
88 * isCompletedAbnormally and isCancelled return false for normally
89 * completed tasks
90 */
91 public void testQuietlyInvoke() {
92 RecursiveAction a = new RecursiveAction() {
93 public void compute() {
94 FibAction f = new FibAction(8);
95 f.quietlyInvoke();
96 threadAssertTrue(f.result == 21);
97 threadAssertTrue(f.isDone());
98 threadAssertFalse(f.isCancelled());
99 threadAssertFalse(f.isCompletedAbnormally());
100 threadAssertTrue(f.getRawResult() == null);
101 }};
102 mainPool.invoke(a);
103 }
104
105 /**
106 * join of a forked task returns when task completes
107 */
108 public void testForkJoin() {
109 RecursiveAction a = new RecursiveAction() {
110 public void compute() {
111 FibAction f = new FibAction(8);
112 f.fork();
113 f.join();
114 threadAssertTrue(f.result == 21);
115 threadAssertTrue(f.isDone());
116 threadAssertTrue(f.getRawResult() == null);
117 }};
118 mainPool.invoke(a);
119 }
120
121 /**
122 * get of a forked task returns when task completes
123 */
124 public void testForkGet() {
125 RecursiveAction a = new RecursiveAction() {
126 public void compute() {
127 try {
128 FibAction f = new FibAction(8);
129 f.fork();
130 f.get();
131 threadAssertTrue(f.result == 21);
132 threadAssertTrue(f.isDone());
133 } catch (Exception ex) {
134 unexpectedException(ex);
135 }
136 }};
137 mainPool.invoke(a);
138 }
139
140 /**
141 * timed get of a forked task returns when task completes
142 */
143 public void testForkTimedGet() {
144 RecursiveAction a = new RecursiveAction() {
145 public void compute() {
146 try {
147 FibAction f = new FibAction(8);
148 f.fork();
149 f.get(5L, TimeUnit.SECONDS);
150 threadAssertTrue(f.result == 21);
151 threadAssertTrue(f.isDone());
152 } catch (Exception ex) {
153 unexpectedException(ex);
154 }
155 }};
156 mainPool.invoke(a);
157 }
158
159 /**
160 * timed get with null time unit throws NPE
161 */
162 public void testForkTimedGetNPE() {
163 RecursiveAction a = new RecursiveAction() {
164 public void compute() {
165 try {
166 FibAction f = new FibAction(8);
167 f.fork();
168 f.get(5L, null);
169 shouldThrow();
170 } catch (NullPointerException success) {
171 } catch (Exception ex) {
172 unexpectedException(ex);
173 }
174 }};
175 mainPool.invoke(a);
176 }
177
178 /**
179 * quietlyJoin of a forked task returns when task completes
180 */
181 public void testForkQuietlyJoin() {
182 RecursiveAction a = new RecursiveAction() {
183 public void compute() {
184 FibAction f = new FibAction(8);
185 f.fork();
186 f.quietlyJoin();
187 threadAssertTrue(f.result == 21);
188 threadAssertTrue(f.isDone());
189 }};
190 mainPool.invoke(a);
191 }
192
193
194 /**
195 * helpQuiesce returns when tasks are complete.
196 * getQueuedTaskCount returns 0 when quiescent
197 */
198 public void testForkHelpQuiesce() {
199 RecursiveAction a = new RecursiveAction() {
200 public void compute() {
201 FibAction f = new FibAction(8);
202 f.fork();
203 f.helpQuiesce();
204 threadAssertTrue(f.result == 21);
205 threadAssertTrue(f.isDone());
206 threadAssertTrue(getQueuedTaskCount() == 0);
207 }};
208 mainPool.invoke(a);
209 }
210
211
212 /**
213 * invoke task throws exception when task completes abnormally
214 */
215 public void testAbnormalInvoke() {
216 RecursiveAction a = new RecursiveAction() {
217 public void compute() {
218 try {
219 FailingFibAction f = new FailingFibAction(8);
220 f.invoke();
221 shouldThrow();
222 } catch (FJException success) {
223 }
224 }};
225 mainPool.invoke(a);
226 }
227
228 /**
229 * quietlyInvoke task returns when task completes abnormally
230 */
231 public void testAbnormalQuietlyInvoke() {
232 RecursiveAction a = new RecursiveAction() {
233 public void compute() {
234 FailingFibAction f = new FailingFibAction(8);
235 f.quietlyInvoke();
236 threadAssertTrue(f.isDone());
237 }};
238 mainPool.invoke(a);
239 }
240
241 /**
242 * join of a forked task throws exception when task completes abnormally
243 */
244 public void testAbnormalForkJoin() {
245 RecursiveAction a = new RecursiveAction() {
246 public void compute() {
247 try {
248 FailingFibAction f = new FailingFibAction(8);
249 f.fork();
250 f.join();
251 shouldThrow();
252 } catch (FJException success) {
253 }
254 }};
255 mainPool.invoke(a);
256 }
257
258 /**
259 * get of a forked task throws exception when task completes abnormally
260 */
261 public void testAbnormalForkGet() {
262 RecursiveAction a = new RecursiveAction() {
263 public void compute() {
264 try {
265 FailingFibAction f = new FailingFibAction(8);
266 f.fork();
267 f.get();
268 shouldThrow();
269 } catch (ExecutionException success) {
270 } catch (Exception ex) {
271 unexpectedException(ex);
272 }
273 }};
274 mainPool.invoke(a);
275 }
276
277 /**
278 * timed get of a forked task throws exception when task completes abnormally
279 */
280 public void testAbnormalForkTimedGet() {
281 RecursiveAction a = new RecursiveAction() {
282 public void compute() {
283 try {
284 FailingFibAction f = new FailingFibAction(8);
285 f.fork();
286 f.get(5L, TimeUnit.SECONDS);
287 shouldThrow();
288 } catch (ExecutionException success) {
289 } catch (Exception ex) {
290 unexpectedException(ex);
291 }
292 }};
293 mainPool.invoke(a);
294 }
295
296 /**
297 * quietlyJoin of a forked task returns when task completes abnormally
298 */
299 public void testAbnormalForkQuietlyJoin() {
300 RecursiveAction a = new RecursiveAction() {
301 public void compute() {
302 FailingFibAction f = new FailingFibAction(8);
303 f.fork();
304 f.quietlyJoin();
305 threadAssertTrue(f.isDone());
306 threadAssertTrue(f.isCompletedAbnormally());
307 threadAssertTrue(f.getException() instanceof FJException);
308 }};
309 mainPool.invoke(a);
310 }
311
312 /**
313 * invoke task throws exception when task cancelled
314 */
315 public void testCancelledInvoke() {
316 RecursiveAction a = new RecursiveAction() {
317 public void compute() {
318 try {
319 FibAction f = new FibAction(8);
320 f.cancel(true);
321 f.invoke();
322 shouldThrow();
323 } catch (CancellationException success) {
324 }
325 }};
326 mainPool.invoke(a);
327 }
328
329 /**
330 * join of a forked task throws exception when task cancelled
331 */
332 public void testCancelledForkJoin() {
333 RecursiveAction a = new RecursiveAction() {
334 public void compute() {
335 try {
336 FibAction f = new FibAction(8);
337 f.cancel(true);
338 f.fork();
339 f.join();
340 shouldThrow();
341 } catch (CancellationException success) {
342 }
343 }};
344 mainPool.invoke(a);
345 }
346
347 /**
348 * get of a forked task throws exception when task cancelled
349 */
350 public void testCancelledForkGet() {
351 RecursiveAction a = new RecursiveAction() {
352 public void compute() {
353 try {
354 FibAction f = new FibAction(8);
355 f.cancel(true);
356 f.fork();
357 f.get();
358 shouldThrow();
359 } catch (CancellationException success) {
360 } catch (Exception ex) {
361 unexpectedException(ex);
362 }
363 }};
364 mainPool.invoke(a);
365 }
366
367 /**
368 * timed get of a forked task throws exception when task cancelled
369 */
370 public void testCancelledForkTimedGet() {
371 RecursiveAction a = new RecursiveAction() {
372 public void compute() {
373 try {
374 FibAction f = new FibAction(8);
375 f.cancel(true);
376 f.fork();
377 f.get(5L, TimeUnit.SECONDS);
378 shouldThrow();
379 } catch (CancellationException success) {
380 } catch (Exception ex) {
381 unexpectedException(ex);
382 }
383 }};
384 mainPool.invoke(a);
385 }
386
387 /**
388 * quietlyJoin of a forked task returns when task cancelled
389 */
390 public void testCancelledForkQuietlyJoin() {
391 RecursiveAction a = new RecursiveAction() {
392 public void compute() {
393 FibAction f = new FibAction(8);
394 f.cancel(true);
395 f.fork();
396 f.quietlyJoin();
397 threadAssertTrue(f.isDone());
398 threadAssertTrue(f.isCompletedAbnormally());
399 threadAssertTrue(f.getException() instanceof CancellationException);
400 }};
401 mainPool.invoke(a);
402 }
403
404 /**
405 * getPool of executing task returns its pool
406 */
407 public void testGetPool() {
408 RecursiveAction a = new RecursiveAction() {
409 public void compute() {
410 threadAssertTrue(getPool() == mainPool);
411 }};
412 mainPool.invoke(a);
413 }
414
415 /**
416 * getPool of non-FJ task returns null
417 */
418 public void testGetPool2() {
419 RecursiveAction a = new RecursiveAction() {
420 public void compute() {
421 threadAssertTrue(getPool() == null);
422 }};
423 a.invoke();
424 }
425
426 /**
427 * inForkJoinPool of executing task returns true
428 */
429 public void testInForkJoinPool() {
430 RecursiveAction a = new RecursiveAction() {
431 public void compute() {
432 threadAssertTrue(inForkJoinPool());
433 }};
434 mainPool.invoke(a);
435 }
436
437 /**
438 * inForkJoinPool of non-FJ task returns false
439 */
440 public void testInForkJoinPool2() {
441 RecursiveAction a = new RecursiveAction() {
442 public void compute() {
443 threadAssertTrue(!inForkJoinPool());
444 }};
445 a.invoke();
446 }
447
448 /**
449 * getPool of current thread in pool returns its pool
450 */
451 public void testWorkerGetPool() {
452 RecursiveAction a = new RecursiveAction() {
453 public void compute() {
454 ForkJoinWorkerThread w =
455 (ForkJoinWorkerThread)(Thread.currentThread());
456 threadAssertTrue(w.getPool() == mainPool);
457 }};
458 mainPool.invoke(a);
459 }
460
461 /**
462 * getPoolIndex of current thread in pool returns 0 <= value < poolSize
463 */
464 public void testWorkerGetPoolIndex() {
465 RecursiveAction a = new RecursiveAction() {
466 public void compute() {
467 ForkJoinWorkerThread w =
468 (ForkJoinWorkerThread)(Thread.currentThread());
469 int idx = w.getPoolIndex();
470 threadAssertTrue(idx >= 0);
471 threadAssertTrue(idx < mainPool.getPoolSize());
472 }};
473 mainPool.invoke(a);
474 }
475
476
477 /**
478 * setRawResult(null) succeeds
479 */
480 public void testSetRawResult() {
481 RecursiveAction a = new RecursiveAction() {
482 public void compute() {
483 setRawResult(null);
484 }};
485 a.invoke();
486 }
487
488 /**
489 * A reinitialized task may be re-invoked
490 */
491 public void testReinitialize() {
492 RecursiveAction a = new RecursiveAction() {
493 public void compute() {
494 FibAction f = new FibAction(8);
495 f.invoke();
496 threadAssertTrue(f.result == 21);
497 threadAssertTrue(f.isDone());
498 threadAssertFalse(f.isCancelled());
499 threadAssertFalse(f.isCompletedAbnormally());
500 f.reinitialize();
501 f.invoke();
502 threadAssertTrue(f.result == 21);
503 }};
504 mainPool.invoke(a);
505 }
506
507 /**
508 * invoke task throws exception after invoking completeExceptionally
509 */
510 public void testCompleteExceptionally() {
511 RecursiveAction a = new RecursiveAction() {
512 public void compute() {
513 try {
514 FibAction f = new FibAction(8);
515 f.completeExceptionally(new FJException());
516 f.invoke();
517 shouldThrow();
518 } catch (FJException success) {
519 }
520 }};
521 mainPool.invoke(a);
522 }
523
524 /**
525 * invoke task suppresses execution invoking complete
526 */
527 public void testComplete() {
528 RecursiveAction a = new RecursiveAction() {
529 public void compute() {
530 FibAction f = new FibAction(8);
531 f.complete(null);
532 f.invoke();
533 threadAssertTrue(f.isDone());
534 threadAssertTrue(f.result == 0);
535 }};
536 mainPool.invoke(a);
537 }
538
539 /**
540 * invokeAll(t1, t2) invokes all task arguments
541 */
542 public void testInvokeAll2() {
543 RecursiveAction a = new RecursiveAction() {
544 public void compute() {
545 FibAction f = new FibAction(8);
546 FibAction g = new FibAction(9);
547 invokeAll(f, g);
548 threadAssertTrue(f.isDone());
549 threadAssertTrue(f.result == 21);
550 threadAssertTrue(g.isDone());
551 threadAssertTrue(g.result == 34);
552 }};
553 mainPool.invoke(a);
554 }
555
556 /**
557 * invokeAll(tasks) with 1 argument invokes task
558 */
559 public void testInvokeAll1() {
560 RecursiveAction a = new RecursiveAction() {
561 public void compute() {
562 FibAction f = new FibAction(8);
563 invokeAll(f);
564 threadAssertTrue(f.isDone());
565 threadAssertTrue(f.result == 21);
566 }};
567 mainPool.invoke(a);
568 }
569
570 /**
571 * invokeAll(tasks) with > 2 argument invokes tasks
572 */
573 public void testInvokeAll3() {
574 RecursiveAction a = new RecursiveAction() {
575 public void compute() {
576 FibAction f = new FibAction(8);
577 FibAction g = new FibAction(9);
578 FibAction h = new FibAction(7);
579 invokeAll(f, g, h);
580 threadAssertTrue(f.isDone());
581 threadAssertTrue(f.result == 21);
582 threadAssertTrue(g.isDone());
583 threadAssertTrue(g.result == 34);
584 threadAssertTrue(h.isDone());
585 threadAssertTrue(h.result == 13);
586 }};
587 mainPool.invoke(a);
588 }
589
590 /**
591 * invokeAll(collection) invokes all tasks in the collection
592 */
593 public void testInvokeAllCollection() {
594 RecursiveAction a = new RecursiveAction() {
595 public void compute() {
596 FibAction f = new FibAction(8);
597 FibAction g = new FibAction(9);
598 FibAction h = new FibAction(7);
599 HashSet set = new HashSet();
600 set.add(f);
601 set.add(g);
602 set.add(h);
603 invokeAll(set);
604 threadAssertTrue(f.isDone());
605 threadAssertTrue(f.result == 21);
606 threadAssertTrue(g.isDone());
607 threadAssertTrue(g.result == 34);
608 threadAssertTrue(h.isDone());
609 threadAssertTrue(h.result == 13);
610 }};
611 mainPool.invoke(a);
612 }
613
614
615 /**
616 * invokeAll(tasks) with any null task throws NPE
617 */
618 public void testInvokeAllNPE() {
619 RecursiveAction a = new RecursiveAction() {
620 public void compute() {
621 try {
622 FibAction f = new FibAction(8);
623 FibAction g = new FibAction(9);
624 FibAction h = null;
625 invokeAll(f, g, h);
626 shouldThrow();
627 } catch (NullPointerException success) {
628 }
629 }};
630 mainPool.invoke(a);
631 }
632
633 /**
634 * invokeAll(t1, t2) throw exception if any task does
635 */
636 public void testAbnormalInvokeAll2() {
637 RecursiveAction a = new RecursiveAction() {
638 public void compute() {
639 try {
640 FibAction f = new FibAction(8);
641 FailingFibAction g = new FailingFibAction(9);
642 invokeAll(f, g);
643 shouldThrow();
644 } catch (FJException success) {
645 }
646 }};
647 mainPool.invoke(a);
648 }
649
650 /**
651 * invokeAll(tasks) with 1 argument throws exception if task does
652 */
653 public void testAbnormalInvokeAll1() {
654 RecursiveAction a = new RecursiveAction() {
655 public void compute() {
656 try {
657 FailingFibAction g = new FailingFibAction(9);
658 invokeAll(g);
659 shouldThrow();
660 } catch (FJException success) {
661 }
662 }};
663 mainPool.invoke(a);
664 }
665
666 /**
667 * invokeAll(tasks) with > 2 argument throws exception if any task does
668 */
669 public void testAbnormalInvokeAll3() {
670 RecursiveAction a = new RecursiveAction() {
671 public void compute() {
672 try {
673 FibAction f = new FibAction(8);
674 FailingFibAction g = new FailingFibAction(9);
675 FibAction h = new FibAction(7);
676 invokeAll(f, g, h);
677 shouldThrow();
678 } catch (FJException success) {
679 }
680 }};
681 mainPool.invoke(a);
682 }
683
684 /**
685 * invokeAll(collection) throws exception if any task does
686 */
687 public void testAbnormalInvokeAllCollection() {
688 RecursiveAction a = new RecursiveAction() {
689 public void compute() {
690 try {
691 FailingFibAction f = new FailingFibAction(8);
692 FibAction g = new FibAction(9);
693 FibAction h = new FibAction(7);
694 HashSet set = new HashSet();
695 set.add(f);
696 set.add(g);
697 set.add(h);
698 invokeAll(set);
699 shouldThrow();
700 } catch (FJException success) {
701 }
702 }};
703 mainPool.invoke(a);
704 }
705
706 /**
707 * tryUnfork returns true for most recent unexecuted task,
708 * and suppresses execution
709 */
710 public void testTryUnfork() {
711 RecursiveAction a = new RecursiveAction() {
712 public void compute() {
713 FibAction g = new FibAction(9);
714 g.fork();
715 FibAction f = new FibAction(8);
716 f.fork();
717 threadAssertTrue(f.tryUnfork());
718 helpQuiesce();
719 threadAssertFalse(f.isDone());
720 threadAssertTrue(g.isDone());
721 }};
722 singletonPool.invoke(a);
723 }
724
725 /**
726 * getSurplusQueuedTaskCount returns > 0 when
727 * there are more tasks than threads
728 */
729 public void testGetSurplusQueuedTaskCount() {
730 RecursiveAction a = new RecursiveAction() {
731 public void compute() {
732 FibAction h = new FibAction(7);
733 h.fork();
734 FibAction g = new FibAction(9);
735 g.fork();
736 FibAction f = new FibAction(8);
737 f.fork();
738 threadAssertTrue(getSurplusQueuedTaskCount() > 0);
739 helpQuiesce();
740 }};
741 singletonPool.invoke(a);
742 }
743
744 /**
745 * peekNextLocalTask returns most recent unexecuted task.
746 */
747 public void testPeekNextLocalTask() {
748 RecursiveAction a = new RecursiveAction() {
749 public void compute() {
750 FibAction g = new FibAction(9);
751 g.fork();
752 FibAction f = new FibAction(8);
753 f.fork();
754 threadAssertTrue(peekNextLocalTask() == f);
755 f.join();
756 threadAssertTrue(f.isDone());
757 helpQuiesce();
758 }};
759 singletonPool.invoke(a);
760 }
761
762 /**
763 * pollNextLocalTask returns most recent unexecuted task
764 * without executing it
765 */
766 public void testPollNextLocalTask() {
767 RecursiveAction a = new RecursiveAction() {
768 public void compute() {
769 FibAction g = new FibAction(9);
770 g.fork();
771 FibAction f = new FibAction(8);
772 f.fork();
773 threadAssertTrue(pollNextLocalTask() == f);
774 helpQuiesce();
775 threadAssertFalse(f.isDone());
776 }};
777 singletonPool.invoke(a);
778 }
779
780 /**
781 * pollTask returns an unexecuted task
782 * without executing it
783 */
784 public void testPollTask() {
785 RecursiveAction a = new RecursiveAction() {
786 public void compute() {
787 FibAction g = new FibAction(9);
788 g.fork();
789 FibAction f = new FibAction(8);
790 f.fork();
791 threadAssertTrue(pollTask() == f);
792 helpQuiesce();
793 threadAssertFalse(f.isDone());
794 threadAssertTrue(g.isDone());
795 }};
796 singletonPool.invoke(a);
797 }
798
799 /**
800 * peekNextLocalTask returns least recent unexecuted task in async mode
801 */
802 public void testPeekNextLocalTaskAsync() {
803 RecursiveAction a = new RecursiveAction() {
804 public void compute() {
805 FibAction g = new FibAction(9);
806 g.fork();
807 FibAction f = new FibAction(8);
808 f.fork();
809 threadAssertTrue(peekNextLocalTask() == g);
810 f.join();
811 helpQuiesce();
812 threadAssertTrue(f.isDone());
813 }};
814 asyncSingletonPool.invoke(a);
815 }
816
817 /**
818 * pollNextLocalTask returns least recent unexecuted task
819 * without executing it, in async mode
820 */
821 public void testPollNextLocalTaskAsync() {
822 RecursiveAction a = new RecursiveAction() {
823 public void compute() {
824 FibAction g = new FibAction(9);
825 g.fork();
826 FibAction f = new FibAction(8);
827 f.fork();
828 threadAssertTrue(pollNextLocalTask() == g);
829 helpQuiesce();
830 threadAssertTrue(f.isDone());
831 threadAssertFalse(g.isDone());
832 }};
833 asyncSingletonPool.invoke(a);
834 }
835
836 /**
837 * pollTask returns an unexecuted task
838 * without executing it, in async mode
839 */
840 public void testPollTaskAsync() {
841 RecursiveAction a = new RecursiveAction() {
842 public void compute() {
843 FibAction g = new FibAction(9);
844 g.fork();
845 FibAction f = new FibAction(8);
846 f.fork();
847 threadAssertTrue(pollTask() == g);
848 helpQuiesce();
849 threadAssertTrue(f.isDone());
850 threadAssertFalse(g.isDone());
851 }};
852 asyncSingletonPool.invoke(a);
853 }
854
855 }