Whenever the producer moves an item into the shared buffer, it sends a signal to
ID: 3830742 • Letter: W
Question
Whenever the producer moves an item into the shared buffer, it sends a signal to main process. Main process enters a “P” in the monitoring table. Similarly, whenever the consumer moves an item from the shared buffer, it sends a signal to main process. Main process then enters a “C” in the monitoring table. When producer and consumer have copied the entire file1, consumer sends a signal to main process. Main process outputs the monitoring table.
Implement the above in the UNIX environment using C or C++. You may need system calls: signal, kill, pause, sleep, semget, semctl, semop, shmget, shmat, shmctl, etc. When sending signals, you should use the two signals defined for users: SIGUSR1 and SIGUSR2 for the producer and consumer respectively
#define N 100 number of slots in the buffer semaphores are a special kind of int typedef int semaphore; Semaphore mutex 1; controls access to critical region Semaphore empty N, counts empty buffer slots Semaphore ful 0; counts full buffer slots void producer(void) int item; while TRUE) TRUE is the constant 1 item produce em() generate something to put in buffer down (); decrement empty count down (&mutex;); enter critical region insert item (item); put new item in buffer up(&mutex;); leave critical region up(&full;); increment count of full slots void consumer (void) int item; while TRUE) infinite loop down(&full;); decrement full count down(&mutex;); enter critical region take item from buffer item remove item up(&mutex;: leave critical region up(); increment count of empty slots consume item(item); do something with the item Figure 2.28. The producer-consumer problem using semaphores.Explanation / Answer
Please find the below two ways for the implementation
way 01:
**************
Signal.c
#include <stdio.h>
#include <stdlib.h>
#include <signal.h> // sigaction(), sigsuspend(), sig*()
#include <unistd.h> // alarm()
void handle_signal(int signal);
void handle_sigalrm(int signal);
void do_sleep(int seconds);
/* Usage example
*
* First, compile and run this program:
* $ gcc signal.c
* $ ./a.out
*
* It will print out its pid. Use it from another terminal to send signals
* $ kill -HUP <pid>
* $ kill -USR1 <pid>
* $ kill -ALRM <pid>
*
* Exit the process with ^C ( = SIGINT) or SIGKILL, SIGTERM
*/
int main() {
struct sigaction sa;
// Print pid, so that we can send signals from other shells
printf("My pid is: %d ", getpid());
// Setup the sighub handler
sa.sa_handler = &handle_signal;
// Restart the system call, if at all possible
sa.sa_flags = SA_RESTART;
// Block every signal during the handler
sigfillset(&sa.sa_mask);
// Intercept SIGHUP and SIGINT
if (sigaction(SIGHUP, &sa, NULL) == -1) {
perror("Error: cannot handle SIGHUP"); // Should not happen
}
if (sigaction(SIGUSR1, &sa, NULL) == -1) {
perror("Error: cannot handle SIGUSR1"); // Should not happen
}
// Will always fail, SIGKILL is intended to force kill your process
if (sigaction(SIGKILL, &sa, NULL) == -1) {
perror("Cannot handle SIGKILL"); // Will always happen
printf("You can never handle SIGKILL anyway... ");
}
if (sigaction(SIGINT, &sa, NULL) == -1) {
perror("Error: cannot handle SIGINT"); // Should not happen
}
for (;;) {
printf(" Sleeping for ~3 seconds ");
do_sleep(3); // Later to be replaced with a SIGALRM
}
}
void handle_signal(int signal) {
const char *signal_name;
sigset_t pending;
// Find out which signal we're handling
switch (signal) {
case SIGHUP:
signal_name = "SIGHUP";
break;
case SIGUSR1:
signal_name = "SIGUSR1";
break;
case SIGINT:
printf("Caught SIGINT, exiting now ");
exit(0);
default:
fprintf(stderr, "Caught wrong signal: %d ", signal);
return;
}
/*
* Please note that printf et al. are NOT safe to use in signal handlers.
* Look for async safe functions.
*/
printf("Caught %s, sleeping for ~3 seconds "
"Try sending another SIGHUP / SIGINT / SIGALRM "
"(or more) meanwhile ", signal_name);
/*
* Indeed, all signals are blocked during this handler
* But, at least on OSX, if you send 2 other SIGHUP,
* only one will be delivered: signals are not queued
* However, if you send HUP, INT, HUP,
* you'll see that both INT and HUP are queued
* Even more, on my system, HUP has priority over INT
*/
do_sleep(3);
printf("Done sleeping for %s ", signal_name);
// So what did you send me while I was asleep?
sigpending(&pending);
if (sigismember(&pending, SIGHUP)) {
printf("A SIGHUP is waiting ");
}
if (sigismember(&pending, SIGUSR1)) {
printf("A SIGUSR1 is waiting ");
}
printf("Done handling %s ", signal_name);
}
void handle_sigalrm(int signal) {
if (signal != SIGALRM) {
fprintf(stderr, "Caught wrong signal: %d ", signal);
}
printf("Got sigalrm, do_sleep() will end ");
}
void do_sleep(int seconds) {
struct sigaction sa;
sigset_t mask;
sa.sa_handler = &handle_sigalrm; // Intercept and ignore SIGALRM
sa.sa_flags = SA_RESETHAND; // Remove the handler after first signal
sigfillset(&sa.sa_mask);
sigaction(SIGALRM, &sa, NULL);
// Get the current signal mask
sigprocmask(0, NULL, &mask);
// Unblock SIGALRM
sigdelset(&mask, SIGALRM);
// Wait with this mask
alarm(seconds);
sigsuspend(&mask);
printf("sigsuspend() returned ");
}
**************
way 02:
prouducer-consumer.c
****************
Execute : gcc foo.c -lpthread && ./a.out
****************
P.S KINDLY FIND THE ABOVE TWO WAYS FOR THE IMPLEMENTATION AND CHOOSE WHICH ONE YOU FEEL EASY
Related Questions
drjack9650@gmail.com
Navigate
Integrity-first tutoring: explanations and feedback only — we do not complete graded work. Learn more.