CS360 Final Exam: May 6, 2004. Answers

Question 1

This is a standard pipe/fork/dup/exec question: Here are ticker.c and onesec.c.
main()
{
  int tochild[2], fromchild[2];
  double d;
  char buf[11];

  if (pipe(tochild) < 0) { perror("pipe"); exit(1); }
  if (pipe(fromchild) < 0) { perror("pipe"); exit(1); }
  
  if (fork() == 0) {
    close(tochild[1]);
    close(fromchild[0]);
    if (dup2(tochild[0], 0) < 0) { perror("dup2"); exit(1); }
    if (dup2(fromchild[1], 1) < 0) { perror("dup2"); exit(1); }
    close(tochild[0]);
    close(fromchild[1]);
    execlp("ticker", "ticker", NULL);
    perror("execlp ticker");
    exit(1);
  } else {
    close(tochild[0]);
    close(fromchild[1]);
    while(1) {
      sleep(1);
      if (write(tochild[1], "\n", 1) != 1) exit(1);
      if (read(fromchild[0], buf, 10) != 10) exit(1);
      buf[10] = '\0';
      sscanf(buf, "%lf", &d);
      printf("%.5lf\n", d);
    }
  }
}

Question 2

Here the key is to make sure that ticker's standard output is closed when it receives a newline. Here's an example:
UNIX> ( sleep 1 ; echo "" ) | ticker | cat /dev/null
Or, perhaps simply modify the above program so that the parent process also closes fromchild[0], and doesn't perform the read() call.

I will take off points for an answer such as:

UNIX> echo "" | ticker | cat /dev/null
Why? Because if ticker writes its stuff before cat executes, it will write into the pipe buffer, and there will be no sigpipe. To hammer this home, look at ticker2.c, which prints out when getchar() returns. Then, if I delay the cat statement for a second, I get the following:
UNIX> echo "" | ticker2 | ( sleep 1 ; cat /dev/null )
Getchar returned a newline
Getchar returned EOF
Since the pipe isn't closed when ticker2 writes its first number, the write() goes into the pipe buffer, and ticker2 continues on, reading the EOF and returning.

Question 3

At the free() statement, a's memory block will consume 24 bytes, starting at 0x6000, b's memory block will consume 24 bytes, starting at 0x6018, and c's memory block will consume 32 bytes, starting at 0x6030. c's block will be corrupted because of the for loop involving b. The only block on the free list will start 0x6050, and will have a size of 8192-24-24-32 = 8112. The
0x600024
0x60040
0x6008100
0x601c101
0x6010102
0x6014103
0x601824
0x602c0
0x6020200
0x6024201
0x6028202
0x602c203
0x6030204
0x60340
0x6038300
0x603c301
0x6040302
0x6044303
0x6048304
0x604c0
0x60508112
0x60540 (NULL)
0x60580 (NULL)
0x605c0
0x60600
0x60640
0x60680
0x606c0
0x60700
0x60740
0x60780
0x607c0
0x60800
After the second free() statement, b will have been freed, but malloc() will try to allocate 16 bytes from the same block. However, it can't put the remaining 8 bytes back onto the free list, since a free list block requires 12 bytes. So, it will instead give all 24 bytes to the user. So b will be unchanged. A, however will be on the free list, and it should be on the front of the freelist:
0x600024
0x60040x6050
0x60080 (NULL)
0x601c101
0x6010102
0x6014103
0x601824
0x602c0
0x6020200
0x6024201
0x6028202
0x602c203
0x6030204
0x60340
0x6038300
0x603c301
0x6040302
0x6044303
0x6048304
0x604c0
0x60508112
0x60540 (NULL)
0x60580x6000
0x605c0
0x60600
0x60640
0x60680
0x606c0
0x60700
0x60740
0x60780
0x607c0
0x60800

Question 4

Part A - False: Certainly, as threads block and unblock, they may do so in unspecified orders, so you can still have race race conditions.

Part B - False: Look at the program print4.c from the first Thread lecture notes. In that program all the printme threads have their i pointer pointing to memory on the main thread's stack. It's perfectly legal, and one of the reasons why a thread's stack is not freed up when the thread exits (unless it is detached or joined).

Part C - True: That was the subject of the lecture on condition variables. In particular, the printer simulation cannot function with only mutexes.

Part D - True: See the lecture notes on condition variables and joining.

Part E - False: Any thread can join with any other. Again, look at the code in the condition variable & joining lecture. The cleaner thread calls pthread_join() on threads that it did not create.

Part F - True: See the lecture notes.

Part G - True: That's most often how mutexes are used.

Part H - False: See the printer simulation -- that's why we changed the if statement into a while.

Part I - True: Remember race.c? That's one of them.

Part J - True: Suppose you want two threads doing something simultaneously that does not require I/O. Then in a preemptive system, you simply fork them off and let them run. In a non-preemptive system, one thread will run forever, shutting out the other.


Question 5

The problem is that you call setjmp() and then return, which means that the stack will be corrupted when the longjmp() returns to it. In the given example, we don't know what id_string will be -- it will be whatever the last argument to do_activity() is. This means that the fprintf() will either seg fault or print garbage (it cannot bus error, because you are dereferencing a (char *), and there cannot be any alignment errors). Similarly, we don't know what buf's value will be. So again, the free() statement can seg fault, bus error, or simply corrupt memory further and return. This is a potentially disastrous bug.

Extra Credit

Here's the hand again.
           Partner
         S J9xx
         H AKJxxx
         D Q
         C xx
LHO                  RHO
           You
         S AKTx
         H Qxxx
         D Ax
         C AQJ

Part 1: You need twelve tricks to make your contract. This is called a "small slam."

Part 2: This is a little tricky. You have no heart losers, so that is six tricks. You have no diamond losers, so that is a seventh trick. You have two spade tricks, and one club. That makes 10. The other two tricks must come from spades or clubs.

Now, suppose LHO leads a club. Your worries are over. If RHO has the king and goes up with it, you have two extra club tricks. If RHO ducks it, or LHO had it, then you will score your club queen, and then you can simply lose a spade and win three spade tricks (yes, you can finesse RHO for it, and if RHO has the queen, you will make all 13 tricks).

Suppose LHO leads a small diamond. Again, your worries are over, because you will win your queen, and again have the luxury of losing a spade trick.

Suppose LHO leads a spade. This is trickier. You will put up the jack. If RHO covers it with the queen, then you're getting 4 spade tricks -- contract made. If RHO ducks the queen, or LHO has the queen, then the jack will take the trick. Now, suppose that happens and spades are splitting 3-2 or 2-3. The ace and king of spades will collect the rest of the spades, and your last spade will be good -- contract made. Suppose instead RHO has four spades (including the queen). Then, when you cash the ace of spades, LHO will show out (you will have drawn trumps, of course), and you can take the marked spade finesse against RHO and make the contract. Suppose LHO has the four spades to the queen. Then you will be able to engineer the endplay that I will talk about below.

So, there are 5 missing spades, 9 missing diamonds that are not the king, and 8 missing clubs. That makes 22. The remaining four cards -- the three missing hearts and the king of diamonds, are the only leads that can put the contract in jeopardy.

Part 3: Ok -- the obvious line is to finesse in spades or clubs (by finesse, I mean play RHO for the QS or JC, and lead low from the dummy. For example, you lead a low club. If RHO has the king and plays low, your jack will win the trick. If RHO plays the king, you will overtake, and your QJ are good.) If either finesse is working, you will make the contract, because you can get the extra two tricks in that suit. If you lose the first finesse you try, that's just one trick -- if the second finesse is working, you'll still make your contract.

However, there is a better line available. Draw trump with the queen and jack, play the ace of diamonds and trump a diamond. Your hands will look like this:

         S J9xx
         H AKxx
         D -
         C xx
LHO                      RHO
           You
         S AKTx
         H xx
         D - 
         C AQJ
Now, cash the AK of spades. If the queen drops, you are done, because your spades are good. If both opponents follow, then you play a third round of spades. Your fourth spade will be good for trick #11. However, you still need trick #12. If LHO has the queen, when he takes it, that will be his last spade, and he is endplayed. If he leads a diamond, you will trump it in your hand and discard a club, and that is your 12th trick (you now have no club losers). (Note this is the same situation that you can engineer if LHO led a spade from Qxxx).

If RHO has the queen, or if spades are 4-1, then you must rely on the club finesse working.

I believe that this is the best line.

Part 4: (3 points): Taking the two finesses is simple to calculate. If the club finesse wins 50% of the time. Of the remaining 50%, the spade finesse will work 50% of the time -- that's 75% success. Actually, if LHO has the singleton queen of spades (4% of the time), you can pick that up too by cashing the AS before taking the spade finesse. So the line is really .5 + .5*(.54) = 0.77%

The other line is much harder to calculate. Suppose the probability of the QS dropping singleton or doubleton is pq. Suppose the probability of LHO having Qxx is px. Then, your probability is:

pq + px + .5(1-pq-px)

The probability of a 3-2 break is 65%. A 4-1 break is 26%. A 5-0 break is 9%. However, we are throwing out chance of a 5-0 break, so the probability of a 3-2 break is 65/91 = 0.71, and of a 4-1 break is .39.

The probability of Qx in either hand is .4(.71) = 0.28

The probability of a singleton queen is .2(.39) = 0.08

The probability of Qxx in either hand is .6(.71) = 0.426, so the probability of LHO having the Qxx is .5(.426) = .21

So, pq = .28 + .08 = .36; px is .21.

So the overall probability is: .28 + .36 + .5(1-.28-.36) = 0.82. That's 82% of the time, which is excellent.

Actually...... Going back to the first line, if you draw trump, cash the ace of diamonds and ace of spades, then trump a diamonds and finesse a spade, then lefty will also be endplayed if he started with queen doubleton. I hadn't thought of that -- That is .71x.5x.4 = 14% of the time, which makes that line 91%!

Of course, at the table (a friend played this, not me), here was the layout:

         S Jxxx
         H AKJxxx
         D Q
         C xx
S Tx               S Qxx
H x                H xx
D Kxxxxxx          D Jxx
C Kxx              C xxxxx

         S AK9x
         H Qxxx
         D Ax
         C AQJ
It's slightly different, but the second line is the best, because you can't make a simple finesse of spades. He played it according to the second line, and went down...