讲解EECS 338、辅导C/C++编程、讲解C/C++语言、辅导bounded-buffer

- 首页 >> C/C++编程

EECS 338 Homework 7

General requirements:

Due at 11:59 PM on the posted due date.

Create a typed report for discussion questions and program output.

Upload a single, compressed file (e.g. zip) to Canvas that contains all required files (programs + report).

All work should be your own, as explained in the Academic Integrity policy from the syllabus.

Include either a single makefile that compiles all programs or a separate makefile for each.

1. Implement a semaphore-based solution for the bounded-buffer problem presented in Section 5.7.1 of the

textbook to analyze the sequence below, and answer the questions that follow. Be sure to use global

variables where appropriate (e.g. semaphores).

a. The parent thread initializes the semaphores (mutex, full, and empty) and creates a child thread.

b. The parent thread is a producer and uses a loop to store N values in a buffer of size N / 2. Use any

values you wish. After producing each value, print a message indicating which loop iteration the parent

is in. For example:

Parent iteration #2

c. The child thread immediately sleeps when created such that the buffer has time to fill up with N / 2

values before proceeding. For example, sleep for 1 or 2 seconds. This is intended to allow a competition

between the producer and consumer after the buffer has filled up.

d. The child thread is a consumer. Upon awakening from the forced sleep, the child thread uses a loop to

read and print N values (one at a time) from the buffer. After consuming each value, print a message

indicating which loop iteration the child is in and the value that was consumed. Below is an example

where the child thread consumed a value “40” during its iteration #3:

Child iteration #3. data = 40

Note that, when this step begins, the child will signal(empty) after consuming its 1st value. This will

unblock the parent and begin a competition between the producer and consumer.

Analysis questions (put responses in your report):

a. What is the output?

b. Based on the output, briefly describe the apparent order of when the parent and child are each

executing their critical sections (between wait(mutex) and signal(mutex)). Do they each take turns

(parent, child, parent, child, etc.) or is there a different pattern? Is it the same every time you run the

program?

c. Provide an explanation for the particular order you observed in (b), based on how the three semaphores

operate.

d. We know that output from concurrent processes does not necessarily prove the order in which they

were executed. Do the following to provide evidence of the exact order of when the parent and child

are each executing their critical sections.

Modify your program in some way to determine the ordering. For example, you could create a global

array to store a history, protected within the critical section (CS), where each thread writes its own ID

value (e.g. 1 for the parent and 2 for the child). An index value (global variable) could be used for

updating the array. In this approach, suppose the actual CS order was parent, child, parent, child, etc.

As the shared index is incremented by the threads, the array would be filled with values {1, 2, 1, 2,

etc.}. Because only one process adds a value to the array at a time, we can deduce the order in which

their CS’s were executed. You could print the array values at the end. You may use a different

approach if you wish.

In your report: (i) Explain how your modification works. (ii) Provide the output. (iii) Explain whether

it agrees with your observations from (b) and explanation from (c).

2. Using 2 producer threads and 2 consumer threads, implement a semaphore-based solution for the boundedbuffer

problem presented in Section 5.7.1 of the textbook. Design and analyze the program as described

? Chris Fietkiewicz

below.

a. The parent thread initializes the semaphores (mutex, full, and empty) and creates 4 child threads (see

below). Tip: If you wish to pass an argument to a child thread, the P-thread example from the textbook

(Fig. 4.9) provides an example and was provided as threads1.c with Lecture #9.

b. Two child threads are producers. Each uses a loop to store N unique values in a buffer of size N / 2

(total of 2N values). Each producer should use different values. After producing each value, print a

message indicating which producer is printing and which loop iteration it is in. For example:

Producer #2, iteration #5

c. The other two child threads are consumers and immediately sleep when created such that the buffer has

time to fill up with N / 2 values before proceeding. For example, sleep for 1 or 2 seconds. This is

intended to allow a competition after the buffer has filled up.

d. Upon awakening from the forced sleep, each of two consumer child threads uses a loop to read and

print N values (one at a time) from the buffer. After consuming each value, print a message indicating

which consumer is printing, the loop iteration it is in, and the value that was consumed. Below is an

example where a consumer thread consumed a value “40” during its iteration #3:

Consumer #1, iteration #3. data = 40

e. Include the same mechanism you used for the problem #1 analysis, part (d), to determine the exact

ordering of when each child thread (producers and consumers) is in its critical section. If you use the

previous suggestion of using an array, you could give each child thread a unique ID number (1, 2, 3, 4)

and have each child store its ID in the array (e.g. 1, 2, 3, 4, 1, 2, 3, 4, etc.). After the parent thread joins

all 4 child threads, it should print this history.

Analysis questions (put responses in your report):

a. What is the output, including any information printed for part (e)?

b. How many CPU cores are you using? (Type “nproc” to get the number.)

c. Based on the output, including the ordering info from part (e), describe the apparent order of when the

producers and consumers each executing their critical sections (between wait(mutex) and

signal(mutex)). Do they each take turns (producer, consumer, producer, consumer, etc.) or is there a

different pattern? Is it the same every time you run the program?

3. Modify the semaphore-based solution for the bounded-buffer problem presented in Section 5.7.1 of the

textbook as shown below. Note that, in the consumer algorithm, the sem_wait and sem_post calls are

reversed (in bold), as compared to the correct algorithm. This version will not work correctly.

Producer (normal):

sem_wait(&empty);

sem_wait(&mutex);

// Critical section

sem_post(&mutex);

sem_post(&full);

Consumer (modified):

sem_wait(&mutex);

sem_wait(&full);

// Critical section

sem_post(&empty);

sem_post(&mutex);

a. Implement this as a program with 2 threads, as in problem #1. You do not need to include a mechanism

for historical analysis, as in the analysis, part (d). What is the output?

b. Explain the behavior of this modified algorithm and why it does not work, in terms of the semaphores.


站长地图