Programming Assignment I Due Date: October 6, 1997 The goal of this programming assignment is to get you started with threads programming. Using the Cthreads library, you will learn how to create threads and how the threads share data and synchronize with each other. You will program a library that allows threads to communicate via messages. Message passing between threads will be implemented via shared memory. More specifically, you will build an application that has a number N of threads that run on M logical processors. These threads can send messages to ports that are numbered from 0..K-1. The calls used for exchanging messages are as follows: send(port_num, data_buffer_address, size_of_data) receive(port_num, buffer_address, size_of_data) The send call should be non-blocking (when possible) and the receive call blocks the thread until a message becomes available on the port number specified by the call. The implementation of these calls will be as follows. Messages sent by threads will be copied in shared buffers and then enqueued on port queues. Thus, a send call must allocate a buffer of desired size from a shared buffer pool, copy the data into the buffer and then enqueue it on the appropriate queue. A thread making a receive call will check the port queue and block if no messages are available. When a message becomes available, the message from the buffer is copied into the memory area specified by the call and the shared buffer is released (i.e., is added to the free pool). A send call may also result in the blocking of the thread executing the call if a buffer cannot be allocated from the shared pool (i.e., insufficient contiguous memory). In addition to the queue data structures for ports, you also need to implement the buffer pool. You can declare a large chunk of memory and then use a scheme like first-fit or best-fit to allocate and free memory as messages are sent and received. Both the buffer pool and the port queues are shared data structures and they need to be accessed after acquiring locks. The mutex_lock and mutex_unlock calls can be used for this purpose. When a thread needs to be blocked (e.g., no message is available for a receive call), the condition_wait call should be used. A condition_signal can be used to unblock such threads. You need to fill in lot of the details to get a working program but you should have at least 8 threads (N >= 8) running on at least two logical processors (M >= 2). Also, the number of ports should be at least 8 (K >= 8). You can choose message sizes but you should not use the same size for all messages exchanged in the application. The threads should exchange a large number of messages before the application terminates.