Errata Sheet

Foundations of Multithreaded, Parallel, and Distributed Programming


p. 13, third line from bottom -- the definition of independent operations is wrong; it should read "Two operations are independent if the write set of each is disjoint from both the read and write sets of the other."

p. 16, line 5 in program at top of page -- c[ij] should be c[i,j]

p. 30, lines 6-8 of text -- A process declaration does not end with the keyword end; the body is enclosed in braces. Thus replace the sentences starting with "It begins with the keyword" by the following:
"It begins with the keyword process. The body of a process is enclosed in braces; it contains declarations of local variables, if any, and a list of statements."

p. 30, second program from the bottom -- in the printf statement in the comment, there should be a quote mark after \n

p. 40, line 2 -- change "@await@" to "await"

p. 40, line 9 -- replace "solved" by "solve"

p. 45, definition (2.1), Independence of Parallel Processes, is wrong -- change the last sentence to: "Two parts of a program are independent if the write set of each part is disjoint from both the read and write sets of the other part."

p. 47, line 7 of second to last paragraph -- the first process in Figure 2.1 is the consumer, and the second process is the producer.

p. 47, last paragraph -- there are actually three buffers. The two buffers referred to in line 5 are the two that are local to the processes (one each); the third is the shared buffer.

p. 48, Figure 2.1, third line of process 2 -- I assume that read returns EOF after the last line of data is read (as in Unix), so change this line to "read next line of input into line2 or set EOF after last line"

p. 49, first sentence after first program fragment -- replace "smaller" by "larger"; the program is looking for a[i] that are larger than the current maximum

p. 51, program display at bottom -- to make the program clearer, change the declaration line to:

     int x, y = 0, z = 0;

p. 52, definition of At-Most-Once Property -- this definition is tricky and leads to lots of confusion. Although it is correct, it would probably be best to say in clause (a) that x is not referenced by another process. A statement such as x = x+1 is certainly not atomic if x is read by another process, and it can lead to confusion if x is written by another process.

p. 56, first paragraph of Section 2.5 -- replace the second and third sentences by the following: "In particular, the producer process repeatedly reads input lines and passes them on to the consumer process. The consumer determines those lines that contain the desired pattern and prints them."

p. 58, fourth line from bottom of page -- change "if formula" to "if a formula"

p. 61, first program fragment below Figure 2.3 -- the text talks about incrementing x, so change "x = 1;" to "x = x+1;"

p. 73 -- lines 2 and 3 of the second to last paragraph -- replace "where GOOD is equivalent to BAD" by "where GOOD is equivalent to not BAD."

p. 84, Exercise 2.12 -- there is a missing oc at the end of second line of the program.

p. 105, 5th line from bottom -- change "(2.4)" to "(2.2)"

pp. 106-8, Figures 3.5, 3.6, and 3.7 -- there is a terrible mistake in the entry protocols for the various versions of the tie-breaker algorithm. In particular, the "in" flags need to be set before last is changed. As a specific example, line 5 of Figure 3.5 should read

     in1 = true; last = 1;   /* entry protocol */
The same kind of change needs to be made in line 14 of Figure 3.5, lines 5 and 14 in Figure 3.6, and line 6 in Figure 3.7. (Somehow I reversed the orders of these pairs of assignments when rewriting this section from my Concurrent Programming book.)

p. 109, fourth line from bottom -- change "likely" to "unlikely"

p. 112, predicate BAKERY at the top of the page -- delete "(turn[i] > 0) =>" from the third line. In words, the predicate should say that if process i is in its critical section, then turn[i]>0 and the value of turn[j] for all other j is either zero or greater than turn[i].

p. 115, line 4 of second program display -- indent "wait" so that it lines up with "code"

p. 142, line 7 of exercise 3.2 -- change "variable" to "var"

p. 143, exercise 3.5 (and exercise 3.6) -- There is a significant oversight in the descriptions of LL and SC. An SC can be allowed to succeed only if it follows an LL executed by the same processor and if there has not been any intervening store to the location. (It is OK if there are multiple LLs from the location, but only one of them can be allowed to have an SC that succeeds.)

Let processor be an additional shared register that contains the identity of the processor that executed the last LL instruction. Then change the definitions of LL and SC to the following:

  LL(register, variable, CPUid)  # load locked
    < register = variable; location = &variable; processor = CPUid; >

  SC(variable, value, CPUid)     # store conditional
    < if (location == &variable && processor == CPUid)
          { variable = value; location = 0; return (1); }
      else
          return (0);  >
In addition, every store instruction needs to invalidate the location register if it stores in the address that was loaded by the most recent LL instruction. In short, every store needs to execute
  if (address == &location)
     location = 0   # some invalid address

p. 145, line 5 -- change "module 3" to "modulo 3"

p. 158, paragraph 1 -- There is a major error in the discussion of using semaphores to implement an N-process barrier. There is a race condition if there is only one semaphore per process; the situation is almost identical to the problem discussed at the top of page 123 for flag barriers. In particular, each process needs to use an array of arrive semaphores, with one semaphore per stage of the barrier. Even though semaphore signals (V operations) are remembered, you still have to ensure that a signal intended for one process is is not seen by another.

p. 185, line 3 -- delete the space between # and include

p. 187, first four lines of Figure 4.15 -- delete the space after #

p. 216, 6 lines from the bottom -- replace "were zero" by "were not zero" in the phrase "a signaled writer would have to go back to sleep if nr were zero."

p. 241, last sentence of third paragraph -- replace the sentence by the following two sentences: "It can also lead to deadlock. If a thread holds the lock on one object and another thread holds the lock on a second object, the threads will deadlock if they both call methods in the object locked by the other." (A thread in Java can, however, call methods in objects for which it already holds the lock.)

p. 248, first five lines of Figure 5.18 -- delete the space after #

p. 273, Figure 6.3 -- there is a missing right brace at the end of the figure

p. 275, procedure join -- add the statement "executing[i] = 0;"

p. 294, line 7 -- change "distributed share memory" to "distributed shared memory"

p. 305, Figure 7.5 -- replace the two instances of res_type by result_type (on lines 5 and 8 of the Figure)

p. 317, Figure 7.13 -- processes P[2] through P[n-2] need to send the result along to the next process. Hence add the following statement after the last receive statement at the bottom of the figure:

     if (i < n-1) send values[i+1](smallest, largest);

p. 338, first two lines of Figure 7.16 -- delete the space after #

p. 341, first line of Figure 7.17 -- delete the space after #

p. 347, line 9 of Figure 7.19 -- change System.ex it(1); to System.exit(1);

p. 367, line 10 -- change "delay and tick" to "delay and the Clock process"

p. 381, Figure 8.10 -- the input statements use incorrect syntax. They should both be programmed as

     in deposit(v) -> othervalue = v; ni

p. 391, Figure 8.15 -- in the send statement at the end of procedure close(), replace FileServer by FileServer[i]

p. 392, last paragraph -- In the third and fourth sentences, the write weight should be n-1, not n-2.

p. 396, line 11 of Figure 8.16 -- delete or comment out the following line:

     System.setSecurityManager(new RMISecurityManager());
This line worked for early versions of Java but causes an exception for current versions, because the default security policy now prevents loading classes over the network.

p. 399, second line from bottom of page -- change "(Section 9.2)" to "(Section 8.2)"

p. 429, Figure 9.2 -- indent the line that begins "print the result" so that it is under the right brace is the previous line

p. 436, line 8 of Figure 9.4 -- the line if (p != q) should be if (p != i or q != j)

p. 442, line 5 of paragraph 4 -- change "and row j of b" to "and column j of b"

p. 450, line 20 of Figure 9.12 -- replace else # k == ECHO { by else { # k == ECHO

p. 462, line 12 of Figure 9.16 -- indent "announce termination and halt;" it is the body of the if statement

p. 464, lines 8-15 of Figure 9.18 -- the indentation is wrong in both the first and second printings of the book. The actions of T[i] upon receiving the token should be

     if (token == nc)
       announce termination and halt;
     if (color[i] == red)
       { color[i] = blue; token = 0; }
     else
       token++;
     set j to index of channel for next edge in cycle C;
     send ch[j](token);

p. 467, Figure 9.20 -- indent the lines "eat;" and "think'" so they line up with the call and send statements

p. 537, program near top of page -- as written, maxdiff will always be 0.0. This is because grid and new are the same when the first for loop terminates. One way to fix the program is to iterate MAXITER-1 times in the first for loop, and then do one last computation of new grid points before computing the maximum difference.

pp. 539-40 -- To use the optimization described at the start of the paragraph that begins at the bottom of p. 539, you have to initialize the boundary values of new to four times the boundary values of grid. This is because the optimization assumes that all points in new are 4 times too large after the first loop, and it compensates by dividing by 16 (multiplying by 0.0625) instead of 4 in the second loop.

p. 583, second paragraph of Historical Notes -- Forsythe and Moler [1967] served as the main source for Section 11.3, not Section 11.2

p. 594, lines 2-6 of Figure 12.1 -- delete the space after #

p. 596, first five lines of Figure 12.2 -- delete the space after #

p. 624, paragraph 3, line 6 -- delete all the white space between "assigned" and "all". (Who knows what happened here!)

p. 632, Figure 12-8 -- indent the line that begins "initialize grid" so that it lines up with do in the next line

p. 647, line 3 of At-Most-Once Property -- delete "x is not written by another process and"

Acknowledgements

I gratefully thank the following individuals for finding some of the above errors -- and for using my book:

Joseph Berrios, Kerry Davis, Rahul Desai, Abhijit Dixit, Brian Hanley, Carl Hauser, David Hemmendinger, Martin Henz, R. Huang, S. Krishnaprasad, Joshua Louie, Aleardo Manacero Jr., Dennis Peters, Guy Tremblay, Richard Walker, Qiong Zhang.


Last updated June 25, 2002