Complete the following code. The goal is to implement the producer-consumer problem. You are expected to extend the provided C code to synchronize the thread operations consumer() and producer() such that an underflow and overflow of the queue is prevented. You are not allowed to change the code for implementing the queue operations, that is the code between lines 25 and 126 as shown in the screenshot. You must complete the missing parts as shown in the screenshot as well as complete the missing codes of producer and consumer. #include #include #include #include #include #include #include #include #define MAX_LENGTH_CAP 100 #define INIT -127 #define UNDERFLOW (0x80 + 0x02) #define OVERFLOW 0x80 + 0x01 #define BADPTR (0x80 + 0x03) #define CONSUMER_TERMINATION_PROBABILITY 40 #define PRODUCER_TERMINATION_PROBABILITY 30 // ============= LOCKED ============ //sem_t ACCESS; // use a mutex instead of a binary semaphore pthread_mutex_t ACCESS = PTHREAD_MUTEX_INITIALIZER; sem_t *FULLSPOTS; sem_t *EMPTYSPOTS; struct timespec remaining; struct timespec requested_time; struct Queue{ unsignedint head; unsignedint tail; unsignedint length; int8_t* data; }; void enqueue(struct Queue *q, char x) { if(q==NULL) { printf("\nequeue()>> bad queue pointer %x\n", BADPTR); return; } if ( q->head == (q->tail + 1) % q->length){ printf("\nenqueue()>> Attempt to overflow the queue at %p was prevented.\n", q); } else{ // Why is the following commented code wrong (hint: checking for the underflow condition): // wrong: q->tail = (q->tail+1) % q->length; q->data[q->tail] = x; q->data[q->tail-1] = x; // because arrays start at index 0 but our queue starts at index 1 we should write q->data[q->tail-1] = x; // now we must increment the tail if(q->tail == q->length){ q->tail = 1; } else{ q->tail = q->tail + 1; // this line must happen before enqueue is interruption } } } char dequeue(struct Queue *q) { char val; if(q==NULL) { printf("\ndequeue()>> bad queue pointer %x\n", BADPTR); return (char) BADPTR; } if(q->head == q->tail){ printf("\ndequeue()>> Attempt to underflow the queue at %p was prevented.\n", q); return (char) UNDERFLOW; } else{ if(!q->data) // as a rule, we always check pointers before we access them { printf("dequeue()>> bad data pointer %x\n", BADPTR); return (char) BADPTR; } val = q->data[q->head-1]; // because arrays start at index 0 but our queue starts at index 1 we should write q->data[q->head-1]; q->data[q->head-1] = INIT; if (q->head == q->length){ q->head = 1; } else{ q->head = q->head + 1; } } return (char) val; } void build(struct Queue **q, unsigned int length) { printf("\nbuild()>> Building a queue of length %d", length); if( (length == 0) || (length > MAX_LENGTH_CAP) ) { printf("\nbuild()>> Invalid length."); return; } struct Queue *ptr=NULL; if ( ! (ptr = (struct Queue*) malloc(sizeof(struct Queue))) ) { printf("\nbuild()>> Failed to allocate memory for the structure."); return; } printf("\nbuild()>> Allocated memory for the structure at the address %p", ptr); if ((ptr->data = (int8_t*) malloc(length*sizeof(int8_t)) ) == NULL ) { printf("\nbuild()>> Failed to allocate memory of size %lu for queue's data", length * sizeof(char)); } ptr->length = length; ptr->head = 1; ptr->tail = 1; printf("\nbuild()>> Initialize all elements of data to %d\n", (int8_t) INIT); for (int i=0; idata[i] = (int8_t) INIT; *q = ptr; } // ================= UNLOCKED ==================== void *producer( void *qptr ) { } void *consumer( void *qptr) { pthread_exit(0); } void closeup(void); int main(int argc, const char * argv[]) { return0; } void closeup(void)

Operations Research : Applications and Algorithms
4th Edition
ISBN:9780534380588
Author:Wayne L. Winston
Publisher:Wayne L. Winston
Chapter23: Simulation With The Excel Add-in @risk
Section23.1: Introduction To @risk: The News Vendor Problem
Problem 4P
icon
Related questions
Question
100%
Complete the following code. The goal is to implement the producer-consumer problem. You are expected to extend the provided C code to synchronize the thread operations consumer() and producer() such that an underflow and overflow of the queue is prevented. You are not allowed to change the code for implementing the queue operations, that is the code between lines 25 and 126 as shown in the screenshot. You must complete the missing parts as shown in the screenshot as well as complete the missing codes of producer and consumer.
 
 
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <time.h>
#include <pthread.h>
#include <semaphore.h>
#include <errno.h>
#include <fcntl.h>
#define MAX_LENGTH_CAP 100
#define INIT -127
#define UNDERFLOW (0x80 + 0x02)
#define OVERFLOW 0x80 + 0x01
#define BADPTR (0x80 + 0x03)
#define CONSUMER_TERMINATION_PROBABILITY 40
#define PRODUCER_TERMINATION_PROBABILITY 30

// ============= LOCKED ============
//sem_t ACCESS; // use a mutex instead of a binary semaphore
pthread_mutex_t ACCESS = PTHREAD_MUTEX_INITIALIZER;
sem_t *FULLSPOTS;
sem_t *EMPTYSPOTS;
struct timespec remaining;
struct timespec requested_time;
struct Queue{
unsignedint head;
unsignedint tail;
unsignedint length;
int8_t* data;
};

void enqueue(struct Queue *q, char x)
{
if(q==NULL)
{
printf("\nequeue()>> bad queue pointer %x\n", BADPTR);
return;
}
if ( q->head == (q->tail + 1) % q->length){
printf("\nenqueue()>> Attempt to overflow the queue at %p was prevented.\n", q);
}
else{
// Why is the following commented code wrong (hint: checking for the underflow condition):
// wrong: q->tail = (q->tail+1) % q->length; q->data[q->tail] = x;

q->data[q->tail-1] = x; // because arrays start at index 0 but our queue starts at index 1 we should write q->data[q->tail-1] = x;
// now we must increment the tail
if(q->tail == q->length){
q->tail = 1;
}
else{
q->tail = q->tail + 1; // this line must happen before enqueue is interruption
}
}
 
}
char dequeue(struct Queue *q)
{
char val;
if(q==NULL)
{
printf("\ndequeue()>> bad queue pointer %x\n", BADPTR);
return (char) BADPTR;
}

if(q->head == q->tail){
printf("\ndequeue()>> Attempt to underflow the queue at %p was prevented.\n", q);
return (char) UNDERFLOW;
}
else{
if(!q->data) // as a rule, we always check pointers before we access them
{
printf("dequeue()>> bad data pointer %x\n", BADPTR);
return (char) BADPTR;
}

val = q->data[q->head-1]; // because arrays start at index 0 but our queue starts at index 1 we should write q->data[q->head-1];
q->data[q->head-1] = INIT;
if (q->head == q->length){
q->head = 1;
}
else{
q->head = q->head + 1;
}
 
}
return (char) val;
}
void build(struct Queue **q, unsigned int length)
{
printf("\nbuild()>> Building a queue of length %d", length);
if( (length == 0) || (length > MAX_LENGTH_CAP) )
{
printf("\nbuild()>> Invalid length.");
return;
}
struct Queue *ptr=NULL;
if ( ! (ptr = (struct Queue*) malloc(sizeof(struct Queue))) )
{
printf("\nbuild()>> Failed to allocate memory for the structure.");
return;
}
printf("\nbuild()>> Allocated memory for the structure at the address %p", ptr);
if ((ptr->data = (int8_t*) malloc(length*sizeof(int8_t)) ) == NULL )
{
printf("\nbuild()>> Failed to allocate memory of size %lu for queue's data", length * sizeof(char));
}
ptr->length = length;
ptr->head = 1;
ptr->tail = 1;
 
printf("\nbuild()>> Initialize all elements of data to %d\n", (int8_t) INIT);
for (int i=0; i<length; i++)
ptr->data[i] = (int8_t) INIT;
*q = ptr;
}

// ================= UNLOCKED ====================

void *producer( void *qptr )
{
 
}

void *consumer( void *qptr)
{
 
pthread_exit(0);
}

void closeup(void);
int main(int argc, const char * argv[])
{
 
return0;
}

void closeup(void)
{

}
C main.c> producer(void *)
327
128 void *producer(void *ptr)
129
130
131
132
133
134
135
136
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
184
185
186
187
188
189
190
191
192
193
172
173
174
175
176
177
178
179 void *consumer( void *ptr)
194
195
196
197
198
199
200
201
202
main.c> producer(void *)
179 void *consumer( void *qptr)
180 {
181
182
203
284
206
207
208
209
210
211
212
213
214
215
216
217
while (1)
218
219
220
221
222
223
printf("\n+++++++++++++PRODUCER BEGIN++++++++++++++++++");
printf("\nproducer() >>Wait for EMPTYSPOTS.");
enqueue ((struct Queue *) qptr, pthread_self()); //thread-id will be sized to fit into the queue element int8_t
pthread_mutex_unlock( &ACCESS );
printf("\n+++++++++++++PRODUCER END++++++++++++++++++++\n\n");
requested_time.tv_nsec= rand()*5* 100000000; // up to 400 miliseconds
requested_time.tv_sec= 5;
}
nanosleep (&requested_time, &remaining);
if (rand() PRODUCER_TERMINATION PROBABILITY == 1){
printf("\n
-PRODUCER CANCELLING-
---"); // What will happen to the consumers? Wait infinitely().
printf("\n\n\nProducer>>Thread %lu terminates normally. What will happen to the consumers?\n", pthread_self());
pthread_cancel(pthread_self());
pthread_exit(0); // Code will not be executed because of the infinite loop
while (1)
printf("\n-
-CONSUMER BEGINN-
printf("\nconsumer() >>Wait for FULLSPOTS.");
Complete this part. You may find some hints in the lines below
printf("\nconsumer()>>Wait for ACCESS.");
// TODD: Complete error checking for pthread_mutex_lock and pthread_mutex_unlock
similar to the error-checking for sem_wait() and sem_post() in this subprogram
pthread_mutex_lock( &ACCESS );
printf("\nConsumer reports %d ", dequeue (qptr));
pthread_mutex_unlock( &ACCESS );
Figure 3 Producer Template
Complete this part. You may find some hints in the lines below
printf("\n\n\nConsumer>>Abnormal Termination will follow because of an attempt to sem post (EMPTYSPOTS) with errno %d\n", errno);
perror("sem_post");
exit(EXIT_FAILURE);
printf("\n-
{
-CONSUMER END-
requested_time.tv_nsec= rand()*5* 100000000;
requested_time.tv_sec = 2 +rand()*3; // 2.. 4 seconds
nanosleep (&requested_time,&remaining);
printf("\n-
printf("\nCONSUMER EXITING-▬▬▬▬▬▬▬
pthread_exit(0);
You can modify these numbers only. If you did, report it in your table that
if(rand()*CONSUMER_TERMINATION PROBABILITY == 1)
CONSUMER CANCELLING--
-"); // What will happen to the producers? Wait infinitely().
printf("\n\n\nConsumer>>Thread %lu terminates normally. What will happen to the producers?\n", pthread_self());
pthread_cancel(pthread_self());
\n\n\n");
Optional. 5% Bonus
"); //never reached
You can modify the values of
requested_time.tv_nsec and requested_time.tv_sec
Figure 4 Consumer Template
Transcribed Image Text:C main.c> producer(void *) 327 128 void *producer(void *ptr) 129 130 131 132 133 134 135 136 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 184 185 186 187 188 189 190 191 192 193 172 173 174 175 176 177 178 179 void *consumer( void *ptr) 194 195 196 197 198 199 200 201 202 main.c> producer(void *) 179 void *consumer( void *qptr) 180 { 181 182 203 284 206 207 208 209 210 211 212 213 214 215 216 217 while (1) 218 219 220 221 222 223 printf("\n+++++++++++++PRODUCER BEGIN++++++++++++++++++"); printf("\nproducer() >>Wait for EMPTYSPOTS."); enqueue ((struct Queue *) qptr, pthread_self()); //thread-id will be sized to fit into the queue element int8_t pthread_mutex_unlock( &ACCESS ); printf("\n+++++++++++++PRODUCER END++++++++++++++++++++\n\n"); requested_time.tv_nsec= rand()*5* 100000000; // up to 400 miliseconds requested_time.tv_sec= 5; } nanosleep (&requested_time, &remaining); if (rand() PRODUCER_TERMINATION PROBABILITY == 1){ printf("\n -PRODUCER CANCELLING- ---"); // What will happen to the consumers? Wait infinitely(). printf("\n\n\nProducer>>Thread %lu terminates normally. What will happen to the consumers?\n", pthread_self()); pthread_cancel(pthread_self()); pthread_exit(0); // Code will not be executed because of the infinite loop while (1) printf("\n- -CONSUMER BEGINN- printf("\nconsumer() >>Wait for FULLSPOTS."); Complete this part. You may find some hints in the lines below printf("\nconsumer()>>Wait for ACCESS."); // TODD: Complete error checking for pthread_mutex_lock and pthread_mutex_unlock similar to the error-checking for sem_wait() and sem_post() in this subprogram pthread_mutex_lock( &ACCESS ); printf("\nConsumer reports %d ", dequeue (qptr)); pthread_mutex_unlock( &ACCESS ); Figure 3 Producer Template Complete this part. You may find some hints in the lines below printf("\n\n\nConsumer>>Abnormal Termination will follow because of an attempt to sem post (EMPTYSPOTS) with errno %d\n", errno); perror("sem_post"); exit(EXIT_FAILURE); printf("\n- { -CONSUMER END- requested_time.tv_nsec= rand()*5* 100000000; requested_time.tv_sec = 2 +rand()*3; // 2.. 4 seconds nanosleep (&requested_time,&remaining); printf("\n- printf("\nCONSUMER EXITING-▬▬▬▬▬▬▬ pthread_exit(0); You can modify these numbers only. If you did, report it in your table that if(rand()*CONSUMER_TERMINATION PROBABILITY == 1) CONSUMER CANCELLING-- -"); // What will happen to the producers? Wait infinitely(). printf("\n\n\nConsumer>>Thread %lu terminates normally. What will happen to the producers?\n", pthread_self()); pthread_cancel(pthread_self()); \n\n\n"); Optional. 5% Bonus "); //never reached You can modify the values of requested_time.tv_nsec and requested_time.tv_sec Figure 4 Consumer Template
Au
#include <pthread.h>
14 #include <semaphore.h>
15 #include <errno.h>
16 #include <fcntl.h>
17 #define MAX_LENGTH_CAP 100 You can modify MAX LENGTH_CAP
18
#define INIT -127
#define UNDERFLOW (0x80+ 0x02)
#define OVERFLOW 0x80+ 0x01
19
26
21
23
24
25
#define BADPTR (0x80 + 0x03)
#define CONSUMER_TERMINATION_PROBABILITY 40
#define PRODUCER_TERMINATION PROBABILITY 30
28
sem_t *FULLSPOTS;
sem_t *EMPTYSPOTS;
30
struct timespec remaining;
31 struct timespec requested_time;
32> struct Queue (-
//sem_t ACCESS; // use a mutex instead of a binary semaphore
pthread_mutex_t ACCESS = PTHREAD_MUTEX_INITIALIZER;
39
40 > void enqueue (struct Queue *q, char x) -
65 char dequeue (struct Queue *q) -
97 > void build (struct Queue **q, unsigned int length) -
125
126 //
127
128 > void *producer( void *qptr)-
179
180 > void *consumer( void *qptr)-
225
226 void closeup (void);
227> int main(int argc, const char * argv[])-
308
309> void closeup (void) -
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
void closeup (void);
int main(int argc, const char * argv[])
struct Queue *qptr = NULL;
build (&qptr, q_test_size);
(&attr);
}
pthread_t thread [6]; // declares the identifier for the thread we will create.
pthread_attr_t attr;
int iret [6];
int q_test_size = 5;
perror("sem_open");
exit (EXIT_FAILURE);
if
You can modify these two constants
for test and experimentation
closeup();
FULLSPOTS = (sem_t*) sem_open("/FULLSPOTS", O_CREAT 10_EXCL, 0644,
if
perror("sem_open");
exit (EXIT_FAILURE);
LOCKED
====== UNLOCKED
EMPTYSPOTS = sem_open("/EMPTYSPOTS", O_CREATIO_EXCL, 0644,
Don't modify this code segment
closeup();
if (qptr->data) free(qptr->data);
if(qptr) free (qptr);
printf("\n");
return 0;
266
267
268
269> void closeup (void) --
}
int x=0;
for(; x<5; x++) {
iret [x] = pthread_create(&thread [x], &attr, producer, qptr); // creat 5 producers
if (!iret [x]) // check for success
printf("PRODUCER_%d was created successfully.", x);
> TOTAL
}
iret [x] = pthread_create(&thread [x], &attr, consumer, qptr); // ctreate one consumer
if (!iret [x])
printf("CONSUMER_%d was created successfully.", x);
for(int x=0; x<6; x++) // Wait for all threads; verify the for-loop
Aa ab, No results
main ⁰A⁰
Figure 2 You must complete the missing parts. between lines 226 - 261 as shown in this screenshot
> TOTAL
Transcribed Image Text:Au #include <pthread.h> 14 #include <semaphore.h> 15 #include <errno.h> 16 #include <fcntl.h> 17 #define MAX_LENGTH_CAP 100 You can modify MAX LENGTH_CAP 18 #define INIT -127 #define UNDERFLOW (0x80+ 0x02) #define OVERFLOW 0x80+ 0x01 19 26 21 23 24 25 #define BADPTR (0x80 + 0x03) #define CONSUMER_TERMINATION_PROBABILITY 40 #define PRODUCER_TERMINATION PROBABILITY 30 28 sem_t *FULLSPOTS; sem_t *EMPTYSPOTS; 30 struct timespec remaining; 31 struct timespec requested_time; 32> struct Queue (- //sem_t ACCESS; // use a mutex instead of a binary semaphore pthread_mutex_t ACCESS = PTHREAD_MUTEX_INITIALIZER; 39 40 > void enqueue (struct Queue *q, char x) - 65 char dequeue (struct Queue *q) - 97 > void build (struct Queue **q, unsigned int length) - 125 126 // 127 128 > void *producer( void *qptr)- 179 180 > void *consumer( void *qptr)- 225 226 void closeup (void); 227> int main(int argc, const char * argv[])- 308 309> void closeup (void) - 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 void closeup (void); int main(int argc, const char * argv[]) struct Queue *qptr = NULL; build (&qptr, q_test_size); (&attr); } pthread_t thread [6]; // declares the identifier for the thread we will create. pthread_attr_t attr; int iret [6]; int q_test_size = 5; perror("sem_open"); exit (EXIT_FAILURE); if You can modify these two constants for test and experimentation closeup(); FULLSPOTS = (sem_t*) sem_open("/FULLSPOTS", O_CREAT 10_EXCL, 0644, if perror("sem_open"); exit (EXIT_FAILURE); LOCKED ====== UNLOCKED EMPTYSPOTS = sem_open("/EMPTYSPOTS", O_CREATIO_EXCL, 0644, Don't modify this code segment closeup(); if (qptr->data) free(qptr->data); if(qptr) free (qptr); printf("\n"); return 0; 266 267 268 269> void closeup (void) -- } int x=0; for(; x<5; x++) { iret [x] = pthread_create(&thread [x], &attr, producer, qptr); // creat 5 producers if (!iret [x]) // check for success printf("PRODUCER_%d was created successfully.", x); > TOTAL } iret [x] = pthread_create(&thread [x], &attr, consumer, qptr); // ctreate one consumer if (!iret [x]) printf("CONSUMER_%d was created successfully.", x); for(int x=0; x<6; x++) // Wait for all threads; verify the for-loop Aa ab, No results main ⁰A⁰ Figure 2 You must complete the missing parts. between lines 226 - 261 as shown in this screenshot > TOTAL
Expert Solution
steps

Step by step

Solved in 7 steps with 5 images

Blurred answer
Knowledge Booster
Stack
Learn more about
Need a deep-dive on the concept behind this application? Look no further. Learn more about this topic, computer-science and related others by exploring similar questions and additional content below.
Similar questions
  • SEE MORE QUESTIONS
Recommended textbooks for you
Operations Research : Applications and Algorithms
Operations Research : Applications and Algorithms
Computer Science
ISBN:
9780534380588
Author:
Wayne L. Winston
Publisher:
Brooks Cole
Microsoft Visual C#
Microsoft Visual C#
Computer Science
ISBN:
9781337102100
Author:
Joyce, Farrell.
Publisher:
Cengage Learning,