Threads

Lab exercises for February 20th.

The goals for this assignment are:

  • Understanding the pthread library

  • Working with ucontext

We will use the same repository as last week: Labs Repo. Click on the link and then accept and merge the pull request.

1. Matrix Add Due Feb 20

In the files, matrix.c, implement a program that uses M threads to add two matrices, each stored in its own binary file, and saving the result into a third file.

$ ./matrix
usage: ./matrix   
$ ./matrix 1 A1 B2
Dimensions do not match!
$ ./matrix 1 A1 B1
Starting thread 139848748009024 (idx = 0)
duration: 0.00
$ ./readmat A1
0 -8 -6 8
0 4 -7 9
1 7 0 5
$ ./readmat B1
1 -6 -2 3
-6 -1 -9 8
-7 8 -5 -5
$ ./readmat A1+B1
1 -14 -8 11
-6 3 -16 17
-6 15 -5 0
$ ./matrix 1 A4 B4
Starting thread 139696590177856 (idx = 0)
duration: 0.36
$ ./matrix 4 A4 B4
Starting thread 140698237380160 (idx = 0)
Starting thread 140698228987456 (idx = 1)
Starting thread 140698220594752 (idx = 2)
Starting thread 140698212202048 (idx = 3)
duration: 0.21
$ ./matrix 8 A4 B4
Starting thread 140559920776768 (idx = 1)
Starting thread 140559912384064 (idx = 2)
Starting thread 140559903991360 (idx = 3)
Starting thread 140559929169472 (idx = 0)
Starting thread 140559895598656 (idx = 4)
Starting thread 140559887205952 (idx = 5)
Starting thread 140559878813248 (idx = 6)
Starting thread 140559870420544 (idx = 7)
duration: 0.23

Requirements/Hints:

  • Time how long it takes to compute the result when you have 8, 4, or a single thread.

  • Leverage spatial locality to ensure the best performance, e.g. split the work by rows in each matrix.

  • Use the program readmat.c to test that your program runs correctly

  • Name the output file based on the two inputs, e.g. <Mat1>+<Mat2>

  • Use gettimeofday(), defined in sys/time.h to get the duration of your program.

struct timeval ts, te;
gettimeofday(&ts, NULL);
...
gettimeofday(&te, NULL);
double time = te.tv_sec - ts.tv_sec + (te.tv_usec - ts.tv_usec)/1.e6;
printf("duration: %.4f\n", time);

The matrices you need to add are stored in a binary file that stores a sequence of integers.

  • The first integer is the number of rows

  • The second integer is the number of columns

  • The remaining integers are the values of the matrix, stored in row-major order.

To test with large matrices, download them from the website (but don’t check them in!)

$ wget https://alinen.net/A4
$ wget https://alinen.net/B4

2. Funny functions Due Feb 23

Implement the following programs based on ucontext.

2.1. Return

In the file, hello_context.c, modify the program so it returns to main after executing f(). Use the code from lecture to help you!

$ ./hello_context
Hello World
End of main

2.2. Alternate

In the file, alternate.c, write a program that alternates between two functions indefinitely.

$ ./alternate
odd:1
even:0
odd:3
even:2
odd:5
^C

Send a signal to the alternate process. In your C file, answer the following questions:

  • What happens when a signal is delivered?

  • How do signals affect the execution of a context?

Hints:

  • Alternate between main and another function.

  • Make your two ucontext variables global so that main can swap to the function, and then the function can swap back to main

  • The example above uses nanosleep to pause inside the loop

  • The example above sets printf to flush immediately (e.g. show output text immediately) to make the output cleaner. This is done with the command setvbuf(stdout, 0, _IOLBF, 0);.

Above, main loops over odd numbers and the function loops over even numbers (see below). Each iteration, they swapcontext.

void nextEven()
{
  struct timespec delay = { 1, 0 };
  for (unsigned int i = 0;; i += 2) {
    printf("even:%d\n", i);
    nanosleep(&delay, 0);
  }
}

2.3. Alarm

Can you write a program that alternates between two functions at a set interval?

In the file, alarm.c, write a program that alternates between two functions at a set interval. Use a kernel timer like in the sig_alarm demo from class.

$ **./alarm**
even:0
even:2
odd:1
odd:3
even:4
even:6
odd:5
odd:7

Hints:

  • Above, we defined two functions in addition to main, nextEven() and nextOdd().

  • The signal handler switches between nextEven and nextOdd using a global variable that specifies which should run

  • After setting up the contexts and signals, main calls pause in an infinite loop.

  • The timer triggers every 2 seconds and each functions sleep 1 second between printing. Thus, we see two prints before switching to the next function.