CPSC 213: Assignment 8

Due Monday Nov 19 2012, 6pm


In this assignment you will gain experience in programming with threads in both Java and C.

Task 1: Use Java Thread Class in FunWithThreads

In the first part of the assignment you do some thread programming in Java using the Thread class. This class was discussed in lecture; now you will use it yourself to understand it at a deeper level. You are provided with a file, FunWithThreads.java, which includes a simplified model of a disk with an operation called read. Unlike disk hardware, this read operation is synchronous. Like disk hardware it takes around 10ms (1/100 of a second) to complete a disk read. During this time the read method waits by sleeping (leaving the CPU idle while it waits).

The program is parameterized by command-line arguments that are listed at the beginning of the class. If you run the class without arguments (or providing incorrect argument syntax), it prints a description of the arguments. You use these arguments to select from one of two different implementations (sequential or threaded). The first of these, sequential, is provided for you. Your first goal is to implement the other: threaded. Your implementation must store the result of calls to read in the val array like the sequential version does.

[Updated wording Fri Nov 16 07:54:56 2012. Using Java's standard Thread interface as described in class, the threaded version should create and start a thread for every read, and then join with these threads to record the read result in the val array.] And so, for example, this version will create 1000 threads to perform 1000 reads. To test your implementation, use the -verbose argument and small number of reads (for example, -count 20) and examine the output. The output comes as a list of number pairs. The first number is a sequence number assigned by the disk read when it completes and the second is a sequence number you assign when you request the read; that is, the argument to the read method. The request number should be monotonically increasing, but you may see some small variation between the request and completion numbers and even some repeated or out-of-order completed sequence numbers. [Update Fri Nov 16 07:55:08 2012. To see more variation, try sleep(1000) instead of sleep(10).]


Task 2: Understand C uthread Control Flow

Your second task is to understand the control flow of the C uthread package by reading the code and using it. This package was discussed in lecture; now you will use it yourself to understand it at a deeper level.

First, read through the C code carefully to understand how it works. You do not need to fully understand the Intel assembly language code parts of the implementation (the asm volatile sections of the code); it's fine to quickly skim those sections without reading them carefully.

Next, compile and run ping_pong.c program, which requires the uthread package. The uthread package runs on Intel x86 machines running Linux, MacOS or Cygwin. You have access to several department servers that run Linux, including {annacis, bowen, deas, lulu}.ugrad.cs.ubc.ca. Compile it with the command

gcc -m32 -g -lpthread -o ping_pong ping_pong.c uthread.c
(To compile on Linux or Cygwin it is necessary to explicitly include the pthread library that is called by the uthread package by adding -lpthread to the gcc command; this parameter is optional on MacOS.)

Explain the output of ping_pong in terms of the execution of the ping and pong threads and the uthread control flow at the procedure level (that is, which procedures are executed in what order).

Then, modify the ping_pong procedure to add a call to uthread_yield in both ping and pong at the end (but inside) of the iteration loop (i.e., just after the i loop, but inside of the j loop). Run this modified program, examine its output and compare it to the previous output. Explain what you see by again describing the execution of the two threads in a detailed fashion including the relevant uthread control flow.

Next, modify the ping_pong procedure again to change the argument to uthread_init from 1 to 2 to change its running environment from a uni-processor to a 2-processor system. Run ping_pong several more times, at least 3 to 5 times, to notice how the output changes each time that you run it. Explain its output as before, with a focus for carefully explaining what the effect of this change is and why it produced the output it did.

Finally, to show your understanding of how the uthread code works, describe the control-flow path involved in creating and starting a new thread by listing the uthread procedures in the order that they will execute starting with the creation of a thread and ending when the thread's start procedure begins executing. You do not need to continue tracing into the pthreads package, or explain the assembly language sections.

Task 3: Change async.c to Use uthread

In the last task, you will return to the async.c code from Lab 7, and change it to use uthread instead of doAsync. Change the Triple struct to remove the result field and now have the add and sub routines return the resulting value as an opaque pointer (void*). Use uthread_join to get this value, to cast it back to its actual type, and to synchronize the three phases of the computation (the inner additions, the subtraction, and the outer addition).

Provided Materials

Handing In

Use the handin program. The assignment directory is a8. Please hand in exactly and only the following files with the specified names.

  1. README.txt that contains
  2. FunWithThreads.java containing your modified version of the provided FunWithThreads.java, as described above
  3. async.c containing your modified version of the provided async.c, as described above

File Format Requirements

Refer to the section of the same name in the second assignment for the file format requirements. All files you handin MUST be plain ASCII text, and all source code MUST compile on the ugrad Linux x86 machines in order to receive credit for it.

Last modified 2012-11-12 19:25