DT 8025 2016 Practical 2

From CERES
Jump to: navigation, search

Objectives

There are three objectives for this practical:

  • Learn about and implement the basic ingredients for concurrency,
  • Implement the mutual exclusion primitives,
  • Use them in implementing a simple access control protocol

Instructions

Submit a single .zip file on blackboard with separate folders, each containing the solutions to the below-specified parts.

For each function in the code, you need to write evidence of test-driven development, both in terms of comments (description, pre- and post-condition and properties) and unit testing test suites (e.g., in CUnit, see below). To show the successful execution of your test suite, also include the XML file resulting from its execution. Include a document (preferably with PDF format) which explains the details about the implementation of each part of the assignment (including details of the implemented functions and what they do).

Part 1: Yield and Taskswitch

Download the Libtask library and run the sample program primes on the Raspberry Pi. This is a simple example with only one thread to execute. There is no way of switching context because there is no invocation to taskyield() which is a function in the library used for switching control between threads. Hence, to be able to switch the control between threads using this library you need to implement two functions. The first function is:

taskyield() 

This is the main function used for cooperative control switch between threads. Implement the function such that it

  • enqueues the current thread in the ready queue,
  • set the state of the thread as "yield",
  • pick the first element in the queue, dequeue it and dispatch it by switching the context of two tasks

In order to switch the context of two threads you need to implement another function in the library, namely:


taskswitch()


This function is used to switch the context of two threads by calling the contextswitch() function in libtask.

Complete the body of these two functions in the library and test your implementation using unit tests.

Part 2: Concurrency and Dining Philosophers

This part of the assignment consists of implementing a sample of dining philosophers (you can find a brief description of the protocol here). In this protocol a group of philosophers are siting around a table and there is a fork placed between each two philosophers. Each philosopher alternates between eating and thinking by going through a set of states. A philosopher can enter the eating state by obtaining the two forks on both sides. The configuration of the protocol with two philosophers and forks can be displayed on the display (or PiFace) by an integer comprising 4 digits:

  • the first and the third digits represent the state of the first and the second forks, respectively; value 0 (for each fork) means free and 1 means taken,
  • the second and fourth digits represent the state of philosopher 1 and philosopher 2, respectively; value 0 means thinking, 1 means hungry (waiting to get one fork), 2 means having one fork, 3 means trying to get the other fork, and 4 means eating (possessing 2 forks).

For example, 1 4 1 1 denotes the situation where the first philosopher is eating with two forks and the second philosopher is hungry and trying to get hold of one fork.

Implement the protocol with two philosophers and forks by implementing following functions.

void phil1() 
void phil2() 

The state of forks and philosophers are implemented as global integer variables to represent the behavior of philosophers (first thinking, then becoming hungry and trying to grab one fork, grabbing a fork when available, then trying to grab the other fork, then grabbing the other fork and eating and finally, going back to the thinking state). Note that the access to the forks (global variables) should be surrounded by locks (there are functions in the libtask for manipulating locks). Each philosopher process is responsible for updating the digit of the corresponding philosopher on the display as well as both forks whenever it makes any change to them.

We assume that the program starts in a blocking state (each philosopher has picked the right hand side fork). Implement the protocol in a way that the deadlock situations can be resolved (using yieldtask() properly) and test your program by providing unit tests.

Back to Course Page