Multithreaded Programming in�Cilk�LECTURE 3
1
Charles E. Leiserson
Supercomputing Technologies Research Group
Computer Science and Artificial Intelligence Laboratory
Massachusetts Institute of Technology
© 2006 by Charles E. Leiserson
Multithreaded Programming in Cilk — LECTURE 3
Minicourse Outline
2
© 2006 by Charles E. Leiserson
Multithreaded Programming in Cilk — LECTURE 3
LECTURE 3
3
© 2006 by Charles E. Leiserson
Multithreaded Programming in Cilk — LECTURE 3
Operating on Returned Values
4
Programmers may sometimes wish to incorporate a value returned from a spawned child into the parent frame by means other than a simple variable assignment.
Cilk achieves this functionality using an internal function, called an inlet, which is executed as a secondary thread on the parent frame when the child returns.
x += spawn foo(a,b,c);
Example:
© 2006 by Charles E. Leiserson
Multithreaded Programming in Cilk — LECTURE 3
Semantics of Inlets
5
int max, ix = -1;
for (i=0; i<1000000; i++) {
}
sync; /* ix now indexes the largest foo(i) */
update ( spawn foo(i), i );
inlet void update ( int val, int index ) {
if (idx == -1 || val > max) {
ix = index; max = val;
}
}
© 2006 by Charles E. Leiserson
Multithreaded Programming in Cilk — LECTURE 3
Semantics of Inlets
6
int max, ix = -1;
inlet void update ( int val, int index ) {
if (idx == -1 || val > max) {
ix = index; max = val;
}
}
for (i=0; i<1000000; i++) {
}
sync; /* ix now indexes the largest foo(i) */
update ( spawn foo(i), i );
© 2006 by Charles E. Leiserson
Multithreaded Programming in Cilk — LECTURE 3
Semantics of Inlets
7
int max, ix = -1;
inlet void update ( int val, int index ) {
if (idx == -1 || val > max) {
ix = index; max = val;
}
}
for (i=0; i<1000000; i++) {
update ( spawn foo(i), i );
}
sync; /* ix now indexes the largest foo(i) */
Cilk provides implicit atomicity among the threads belonging to the same frame, and thus no locking is necessary to avoid data races.
© 2006 by Charles E. Leiserson
Multithreaded Programming in Cilk — LECTURE 3
Implicit Inlets
8
cilk int wfib(int n) {
if (n == 0) {
return 0;
} else {
int i, x = 1;
for (i=0; i<=n-2; i++) {
x += spawn wfib(i);
}
sync;
return x;
}
}
For assignment operators, the Cilk compiler automatically generates an implicit inlet to perform the update.
© 2006 by Charles E. Leiserson
Multithreaded Programming in Cilk — LECTURE 3
LECTURE 3
9
© 2006 by Charles E. Leiserson
Multithreaded Programming in Cilk — LECTURE 3
Computing a Product
10
p = ∏ Ai
i = 0
n
int product(int *A, int n) {
int i, p=1;
for (i=0; i<n; i++) {
p *= A[i];
}
return p;
}
Optimization: Quit early if the partial product ever becomes 0.
© 2006 by Charles E. Leiserson
Multithreaded Programming in Cilk — LECTURE 3
Computing a Product
11
p = ∏ Ai
i = 0
n
int product(int *A, int n) {
int i, p=1;
for (i=0; i<n; i++) {
p *= A[i];
}
return p;
}
if (p == 0) break;
Optimization: Quit early if the partial product ever becomes 0.
© 2006 by Charles E. Leiserson
Multithreaded Programming in Cilk — LECTURE 3
Computing a Product in Parallel
12
p = ∏ Ai
i = 0
n
cilk int prod(int *A, int n) {
int p = 1;
if (n == 1) {
return A[0];
} else {
p *= spawn product(A, n/2);
p *= spawn product(A+n/2, n-n/2);
sync;
return p;
}
}
How do we quit early if we discover a zero?
© 2006 by Charles E. Leiserson
Multithreaded Programming in Cilk — LECTURE 3
Cilk’s Abort Feature
13
cilk int product(int *A, int n) {
int p = 1;
inlet void mult(int x) {
p *= x;
return;
}
if (n == 1) {
return A[0];
} else {
mult( spawn product(A, n/2) );
mult( spawn product(A+n/2, n-n/2) );
sync;
return p;
}
}
1. Recode the implicit inlet to make it explicit.
© 2006 by Charles E. Leiserson
Multithreaded Programming in Cilk — LECTURE 3
Cilk’s Abort Feature
14
cilk int product(int *A, int n) {
int p = 1;
inlet void mult(int x) {
p *= x;
return;
}
if (n == 1) {
return A[0];
} else {
mult( spawn product(A, n/2) );
mult( spawn product(A+n/2, n-n/2) );
sync;
return p;
}
}
2. Check for 0 within the inlet.
© 2006 by Charles E. Leiserson
Multithreaded Programming in Cilk — LECTURE 3
Cilk’s Abort Feature
15
cilk int product(int *A, int n) {
int p = 1;
inlet void mult(int x) {
p *= x;
return;
}
if (n == 1) {
return A[0];
} else {
mult( spawn product(A, n/2) );
mult( spawn product(A+n/2, n-n/2) );
sync;
return p;
}
}
cilk int product(int *A, int n) {
int p = 1;
inlet void mult(int x) {
p *= x;
if (p == 0) {
abort; /* Aborts existing children, */
} /* but not future ones. */
return;
}
if (n == 1) {
return A[0];
} else {
mult( spawn product(A, n/2) );
mult( spawn product(A+n/2, n-n/2) );
sync;
return p;
}
}
2. Check for 0 within the inlet.
© 2006 by Charles E. Leiserson
Multithreaded Programming in Cilk — LECTURE 3
Cilk’s Abort Feature
16
cilk int product(int *A, int n) {
int p = 1;
inlet void mult(int x) {
p *= x;
if (p == 0) {
abort; /* Aborts existing children, */
} /* but not future ones. */
return;
}
if (n == 1) {
return A[0];
} else {
mult( spawn product(A, n/2) );
mult( spawn product(A+n/2, n-n/2) );
sync;
return p;
}
}
© 2006 by Charles E. Leiserson
Multithreaded Programming in Cilk — LECTURE 3
Cilk’s Abort Feature
17
cilk int product(int *A, int n) {
int p = 1;
inlet void mult(int x) {
p *= x;
return;
}
if (n == 1) {
return A[0];
} else {
mult( spawn product(A, n/2) );
mult( spawn product(A+n/2, n-n/2) );
sync;
return p;
}
}
cilk int product(int *A, int n) {
int p = 1;
inlet void mult(int x) {
p *= x;
if (p == 0) {
abort; /* Aborts existing children, */
} /* but not future ones. */
return;
}
if (n == 1) {
return A[0];
} else {
mult( spawn product(A, n/2) );
if (p == 0) { /* Don’t spawn if we’ve */
return 0; /* already aborted! */
}
mult( spawn product(A+n/2, n-n/2) );
sync;
return p;
}
}
Implicit atomicity eases reasoning about races.
© 2006 by Charles E. Leiserson
Multithreaded Programming in Cilk — LECTURE 3
LECTURE 3
18
© 2006 by Charles E. Leiserson
Multithreaded Programming in Cilk — LECTURE 3
Min-Max Search
19
© 2006 by Charles E. Leiserson
Multithreaded Programming in Cilk — LECTURE 3
Alpha-Beta Pruning
20
5
2
9
7
4
8
3
6
4
IDEA: If MAX ■ discovers a move so good that MIN ● would never allow that position, MAX’s other children need not be searched — beta cutoff.
© 2006 by Charles E. Leiserson
Multithreaded Programming in Cilk — LECTURE 3
Alpha-Beta Pruning
21
5
2
9
7
4
8
3
6
4
IDEA: If MAX ■ discovers a move so good that MIN ● would never allow that position, MAX’s other children need not be searched — beta cutoff.
© 2006 by Charles E. Leiserson
Multithreaded Programming in Cilk — LECTURE 3
Alpha-Beta Pruning
22
5
2
9
7
4
8
3
6
4
IDEA: If MAX ■ discovers a move so good that MIN ● would never allow that position, MAX’s other children need not be searched — beta cutoff.
© 2006 by Charles E. Leiserson
Multithreaded Programming in Cilk — LECTURE 3
Alpha-Beta Pruning
23
5
2
9
7
4
8
3
6
4
IDEA: If MAX ■ discovers a move so good that MIN ● would never allow that position, MAX’s other children need not be searched — beta cutoff.
© 2006 by Charles E. Leiserson
Multithreaded Programming in Cilk — LECTURE 3
Alpha-Beta Pruning
24
5
2
9
7
4
8
3
6
4
3
IDEA: If MAX ■ discovers a move so good that MIN ● would never allow that position, MAX’s other children need not be searched — beta cutoff.
© 2006 by Charles E. Leiserson
Multithreaded Programming in Cilk — LECTURE 3
Alpha-Beta Pruning
25
5
2
9
7
4
8
3
6
4
3
3
IDEA: If MAX ■ discovers a move so good that MIN ● would never allow that position, MAX’s other children need not be searched — beta cutoff.
© 2006 by Charles E. Leiserson
Multithreaded Programming in Cilk — LECTURE 3
Alpha-Beta Pruning
26
5
2
9
7
4
8
3
6
4
3
6
IDEA: If MAX ■ discovers a move so good that MIN ● would never allow that position, MAX’s other children need not be searched — beta cutoff.
© 2006 by Charles E. Leiserson
Multithreaded Programming in Cilk — LECTURE 3
Alpha-Beta Pruning
27
5
2
9
7
4
8
3
6
4
3
6
IDEA: If MAX ■ discovers a move so good that MIN ● would never allow that position, MAX’s other children need not be searched — beta cutoff.
© 2006 by Charles E. Leiserson
Multithreaded Programming in Cilk — LECTURE 3
Alpha-Beta Pruning
28
5
2
9
7
4
8
3
6
4
3
6
IDEA: If MAX ■ discovers a move so good that MIN ● would never allow that position, MAX’s other children need not be searched — beta cutoff.
© 2006 by Charles E. Leiserson
Multithreaded Programming in Cilk — LECTURE 3
Alpha-Beta Pruning
29
5
6
2
9
7
4
8
3
6
4
3
6
IDEA: If MAX ■ discovers a move so good that MIN ● would never allow that position, MAX’s other children need not be searched — beta cutoff.
© 2006 by Charles E. Leiserson
Multithreaded Programming in Cilk — LECTURE 3
Alpha-Beta Pruning
30
5
6
2
9
7
4
8
3
6
4
3
6
IDEA: If MAX ■ discovers a move so good that MIN ● would never allow that position, MAX’s other children need not be searched — beta cutoff.
© 2006 by Charles E. Leiserson
Multithreaded Programming in Cilk — LECTURE 3
Alpha-Beta Pruning
31
5
6
2
9
7
4
8
3
6
4
3
6
IDEA: If MAX ■ discovers a move so good that MIN ● would never allow that position, MAX’s other children need not be searched — beta cutoff.
© 2006 by Charles E. Leiserson
Multithreaded Programming in Cilk — LECTURE 3
Alpha-Beta Pruning
32
5
6
2
9
7
4
8
3
6
4
3
6
2
IDEA: If MAX ■ discovers a move so good that MIN ● would never allow that position, MAX’s other children need not be searched — beta cutoff.
© 2006 by Charles E. Leiserson
Multithreaded Programming in Cilk — LECTURE 3
Alpha-Beta Pruning
33
5
6
2
9
2
7
4
8
3
6
4
3
6
IDEA: If MAX ■ discovers a move so good that MIN ● would never allow that position, MAX’s other children need not be searched — beta cutoff.
© 2006 by Charles E. Leiserson
Multithreaded Programming in Cilk — LECTURE 3
Alpha-Beta Pruning
34
5
6
2
9
2
7
4
8
3
6
4
3
6
¸6
5
✁
IDEA: If MAX ■ discovers a move so good that MIN ● would never allow that position, MAX’s other children need not be searched — beta cutoff.
© 2006 by Charles E. Leiserson
Multithreaded Programming in Cilk — LECTURE 3
Alpha-Beta Pruning
35
5
6
2
9
2
7
4
8
3
6
4
3
6
¸6
5
✁
IDEA: If MAX ■ discovers a move so good that MIN ● would never allow that position, MAX’s other children need not be searched — beta cutoff.
© 2006 by Charles E. Leiserson
Multithreaded Programming in Cilk — LECTURE 3
Alpha-Beta Pruning
36
5
6
2
9
2
7
4
8
3
6
4
3
6
¸6
5
✁
IDEA: If MAX ■ discovers a move so good that MIN ● would never allow that position, MAX’s other children need not be searched — beta cutoff.
© 2006 by Charles E. Leiserson
Multithreaded Programming in Cilk — LECTURE 3
Alpha-Beta Pruning
37
5
6
2
9
2
7
4
8
3
6
4
3
6
¸6
5
✁
IDEA: If MAX ■ discovers a move so good that MIN ● would never allow that position, MAX’s other children need not be searched — beta cutoff.
© 2006 by Charles E. Leiserson
Multithreaded Programming in Cilk — LECTURE 3
Alpha-Beta Pruning
38
5
6
2
9
2
7
4
8
¸6
3
6
4
3
6
¸6
5
✁
✁
✁
4
8
IDEA: If MAX ■ discovers a move so good that MIN ● would never allow that position, MAX’s other children need not be searched — beta cutoff.
© 2006 by Charles E. Leiserson
Multithreaded Programming in Cilk — LECTURE 3
Alpha-Beta Pruning
39
5
6
2
9
2
7
4
8
3
6
4
3
6
¸6
5
✁
¸6
✁
✁
4
8
Unfortunately, this heuristic is inherently serial.
IDEA: If MAX ■ discovers a move so good that MIN ● would never allow that position, MAX’s other children need not be searched — beta cutoff.
© 2006 by Charles E. Leiserson
Multithreaded Programming in Cilk — LECTURE 3
Parallel Min-Max Search
40
OBSERVATION: In a best-ordered tree, the degree of every internal node is either 1 or maximal.
IDEA: [Feldman-Mysliwietz-Monien 91] If the first child fails to generate a cutoff, speculate that the remaining children can be searched in parallel without wasting any work: “young brothers wait.”
© 2006 by Charles E. Leiserson
Multithreaded Programming in Cilk — LECTURE 3
Parallel Alpha-Beta (I)
41
cilk int search(position *prev, int move, int depth) {
position cur; /* Current position */
int bestscore = -INF; /* Best score so far */
int num_moves; /* Number of children */
int mv; /* Index of child */
int sc; /* Child’s score */
int cutoff = FALSE; /* Have we seen a cutoff? */
#Cilk keywords used so far
1
© 2006 by Charles E. Leiserson
Multithreaded Programming in Cilk — LECTURE 3
Parallel Alpha-Beta (II)
42
inlet void get_score(int child_sc) {
child_sc = -child_sc; /* Negamax */
if (child_sc > bestscore) {
bestscore = child_sc;
if (child_sc > cur.alpha) {
cur.alpha = child_sc;
if (child_sc >= cur.beta) { /* Beta cutoff */
cutoff = TRUE; /* No need to search more */
abort; /* Terminate other children */
}
}
}
}
1
2
3
© 2006 by Charles E. Leiserson
Multithreaded Programming in Cilk — LECTURE 3
Parallel Alpha-Beta (III)
43
/* Create current position and set up for search */
make_move(prev, move, &cur);
sc = eval(&cur); /* Static evaluation */
if ( abs(sc)>=MATE || depth<=0 ) { /* Leaf node */
return (sc);
}
cur.alpha = -prev->beta; /* Negamax */
cur.beta = -prev->alpha;
/* Generate moves, hopefully in best-first order*/
num_moves = gen_moves(&cur);
3
© 2006 by Charles E. Leiserson
Multithreaded Programming in Cilk — LECTURE 3
Parallel Alpha-Beta (IV)
44
/* Search the moves */
for (mv=0; !cutoff && mv<num_moves; mv++) {
get_score( spawn search(&cur, mv, depth-1) );
if (mv==0) sync; /* Young brothers wait */
}
sync;
return (bestscore);
}
3
4
5
6
© 2006 by Charles E. Leiserson
Multithreaded Programming in Cilk — LECTURE 3
LECTURE 3
45
© 2006 by Charles E. Leiserson
Multithreaded Programming in Cilk — LECTURE 3
Mutual Exclusion
46
Cilk’s solution to mutual exclusion is no better than anybody else’s.
Cilk provides a library of spin locks declared with Cilk_lockvar.
Fortunately, Cilk’s control parallelism often mitigates the need for extensive locking.
© 2006 by Charles E. Leiserson
Multithreaded Programming in Cilk — LECTURE 3
Cilk’s Memory Model
47
Programmers may also synchronize through memory using lock-free protocols, although Cilk is agnostic on consistency model.
To aid portability, the Cilk_fence() function implements a memory barrier on machines with weak memory models.
© 2006 by Charles E. Leiserson
Multithreaded Programming in Cilk — LECTURE 3
Debugging Data Races
48
Cilk’s Nondeterminator debugging tool provably guarantees to detect and localize data-race bugs.
FAIL
Information localizing a data race.
PASS
Every execution produces the same result.
Input data set
“Abelian”
Cilk program
A data race occurs whenever two logically parallel threads, holding no locks in common, access the same location and one of the threads modifies the location.
© 2006 by Charles E. Leiserson
Multithreaded Programming in Cilk — LECTURE 3
LECTURE 3
49
© 2006 by Charles E. Leiserson
Multithreaded Programming in Cilk — LECTURE 3
Compiling Cilk
50
Cilk
source
cilk2c
C post-
source
source-to-source
translator
gcc
object
code
C compiler
ld
Cilk
RTS
binary
linking
loader
cilk2c translates straight C code into identical C postsource.
The cilkc compiler encapsulates the process.
© 2006 by Charles E. Leiserson
Multithreaded Programming in Cilk — LECTURE 3
Cilk’s Compiler Strategy
51
SLOW
FAST
FAST
FAST
FAST
FAST
The cilk2c translator generates two “clones” of each Cilk procedure:
© 2006 by Charles E. Leiserson
Multithreaded Programming in Cilk — LECTURE 3
Compiling spawn — Fast Clone
52
suspend
parent
run child
resume
parent
remotely
cilk2c
x = spawn fib(n-1);
Cilk
source
frame->entry = 1;
frame->n = n;
push(frame);
x = fib(n-1);
if (pop()==FAILURE) {
frame->x = x;
frame->join--;
h clean up &
return to scheduler i
}
C post-
source
entry
join
n
x
y
entry
join
Cilk
deque
frame
© 2006 by Charles E. Leiserson
Multithreaded Programming in Cilk — LECTURE 3
Compiling sync — Fast Clone
53
No synchronization overhead in the fast clone!
sync;
cilk2c
Cilk
source
;
C post-
source
SLOW
FAST
FAST
FAST
FAST
FAST
© 2006 by Charles E. Leiserson
Multithreaded Programming in Cilk — LECTURE 3
Compiling the Slow Clone
54
void fib_slow(fib_frame *frame) {
int n,x,y;
switch (frame->entry) {
case 1: goto L1;
case 2: goto L2;
case 3: goto L3;
}
frame->entry = 1;
frame->n = n;
push(frame);
x = fib(n-1);
if (pop()==FAILURE) {
frame->x = x;
frame->join--;
h clean up &
return to scheduler i
}
if (0) {
L1:;
n = frame->n;
}
}
entry
join
n
x
y
entry
join
Cilk
deque
restore
program
counter
continue
same
as fast
clone
restore local
variables
if resuming
frame
© 2006 by Charles E. Leiserson
Multithreaded Programming in Cilk — LECTURE 3
Breakdown of Work Overhead
55
C
state saving
frame allocation
stealing protocol
MIPS R10000
UltraSPARC I
Pentium Pro
Alpha 21164
T1/TS
Benchmark: fib on one processor.
0
27ns
1
2
3
4
5
6
7
78ns
113ns
115ns
(circa 1997)
© 2006 by Charles E. Leiserson
Multithreaded Programming in Cilk — LECTURE 3
LECTURE 3
56
© 2006 by Charles E. Leiserson
Multithreaded Programming in Cilk — LECTURE 3
The JCilk System
57
JCilk to Jgo
Jgo�Compiler
JVM
JCilk RTS
Fib.jcilk
Fib.jgo
JCilk Compiler
Fib.class
© 2006 by Charles E. Leiserson
Multithreaded Programming in Cilk — LECTURE 3
JCilk Keywords
58
cilk
spawn
sync
SYNCHED
inlet
abort
Same as Cilk, except that cilk can also modify try.
Eliminated!
JCilk leverages Java’s exception mechanism to render two Cilk keywords unnecessary.
© 2006 by Charles E. Leiserson
Multithreaded Programming in Cilk — LECTURE 3
Exception Handling in Java
59
“During the process of throwing an exception, the Java virtual machine abruptly completes, one by one, any expressions, statements, method and constructor invocations, initializers, and field initialization expressions that have begun but not completed execution in the current thread. This process continues until a handler is found that indicates that it handles that particular exception by naming the class of the exception or a superclass of the class of the exception.”
— J. Gosling, B Joy, G. Steele, and G. Bracha, � Java Language Specification, 2000, pp. 219–220.
© 2006 by Charles E. Leiserson
Multithreaded Programming in Cilk — LECTURE 3
Exception Handling in JCilk
60
private cilk void foo() throws IOException {
spawn A();
cilk try {
spawn B();
cilk try {
spawn C();
} catch(ArithmeticEx’n e) {
doSomething();
}
} catch(RuntimeException e) {
doSomethingElse();
}
spawn D();
doYetSomethingElse();
sync;
}
© 2006 by Charles E. Leiserson
Multithreaded Programming in Cilk — LECTURE 3
Exception Handling in JCilk
61
private cilk void foo() throws IOException {
spawn A();
cilk try {
spawn B();
cilk try {
spawn C();
} catch(ArithmeticEx’n e) {
doSomething();
}
} catch(RuntimeException e) {
doSomethingElse();
}
spawn D();
doYetSomethingElse();
sync;
}
Exception!
An exception causes all subcomputations dynamically enclosed by the catching clause to abort!
© 2006 by Charles E. Leiserson
Multithreaded Programming in Cilk — LECTURE 3
Exception Handling in JCilk
62
private cilk void foo() throws IOException {
spawn A();
cilk try {
spawn B();
cilk try {
spawn C();
} catch(ArithmeticEx’n e) {
doSomething();
}
} catch(RuntimeException e) {
doSomethingElse();
}
spawn D();
doYetSomethingElse();
sync;
}
An exception causes all subcomputations dynamically enclosed by the catching clause to abort!
ArithmeticEx’n
Nothing aborts.
© 2006 by Charles E. Leiserson
Multithreaded Programming in Cilk — LECTURE 3
Exception Handling in JCilk
63
private cilk void foo() throws IOException {
spawn A();
cilk try {
spawn B();
cilk try {
spawn C();
} catch(ArithmeticEx’n e) {
doSomething();
}
} catch(RuntimeException e) {
doSomethingElse();
}
spawn D();
doYetSomethingElse();
sync;
}
An exception causes all subcomputations dynamically enclosed by the catching clause to abort!
RuntimeEx’n
© 2006 by Charles E. Leiserson
Multithreaded Programming in Cilk — LECTURE 3
Exception Handling in JCilk
64
private cilk void foo() throws IOException {
spawn A();
cilk try {
spawn B();
cilk try {
spawn C();
} catch(ArithmeticEx’n e) {
doSomething();
}
} catch(RuntimeException e) {
doSomethingElse();
}
spawn D();
doYetSomethingElse();
sync;
}
IOException
An exception causes all subcomputations dynamically enclosed by the catching clause to abort!
© 2006 by Charles E. Leiserson
Multithreaded Programming in Cilk — LECTURE 3
Exception Handling in JCilk
65
private cilk void foo() throws IOException {
spawn A();
cilk try {
spawn B();
cilk try {
spawn C();
} catch(ArithmeticEx’n e) {
doSomething();
}
} catch(RuntimeException e) {
doSomethingElse();
}
spawn D();
doYetSomethingElse();
sync;
}
RuntimeEx’n
The appropriate catch clause is executed only after all spawned methods within the corresponding try block terminate.
RuntimeEx’n
© 2006 by Charles E. Leiserson
Multithreaded Programming in Cilk — LECTURE 3
JCilk’s Exception Mechanism
66
© 2006 by Charles E. Leiserson
Multithreaded Programming in Cilk — LECTURE 3
LECTURE 3
67
© 2006 by Charles E. Leiserson
Multithreaded Programming in Cilk — LECTURE 3
Future Work
Adaptive computing
Integrating Cilk with static threads
68
© 2006 by Charles E. Leiserson
Multithreaded Programming in Cilk — LECTURE 3
Key Ideas
69
© 2006 by Charles E. Leiserson
Multithreaded Programming in Cilk — LECTURE 3
Open-Cilk Consortium
70
© 2006 by Charles E. Leiserson
Multithreaded Programming in Cilk — LECTURE 3
ACM Symposium on Parallelism in Algorithms and Architectures
71
Cambridge, MA, USA �July 30 – August 2, 2006
SPAA 2006
© 2006 by Charles E. Leiserson
Multithreaded Programming in Cilk — LECTURE 3