C/C++ 编程代写
当前位置:以往案例 > >案例CS:C语言案例之Make 3 programs/Hitting a pinata Game
2018-11-07

Overview:

An adult (the gameOfficial) lets some number of children take turns hitting a pinata. With probability 1/20 (as computed by a pinata process) the pinata will bust, and the winning child get all the candy.

In this project we'll make 3 programs:

a. A pinata program that waits until it receives SIGUSR1. It will then

o send SIGUSR1 with probability 19/20, or

o send SIGUSR2 with probability 1/20

to the process that signalled it.

b. A child program who hits the pinata.

o It waits for its parent process (the gameOfficial) to send it SIGUSR1 and tell the child that it is that child's turn.

o It then sends SIGUSR1 to the pinata-processes.

o If it gets back SIGUSR1 it knows it failed to break the pinata, and it sends SIGUSR1 back to the gameOfficial.

o However, if it gets back SIGUSR2 is knows it did break the pinata, and it sends SIGUSR2 back to the gameOfficial.

c. A gameOfficial program.

o It asks the user for:

§ the number of pinata-whacking children to make

o It makes all the processes

o It regulates the game, and

o It tells the processes to end after the game is finished.

project:

1. pinata.c

The pinata's job is to wait for a child to whack it and/or to wait to be told to stop:

o Children whack the pinata by sending it SIGUSR1.

o The gameOfficial tells the pinata to stop by sending SIGINT.

Upon receipt of SIGUSR1 the pinata sees if it broke:

o There is a 19/20 chance that the pinata survives, this causes SIGUSR1 to be sent back to the sender.

o There is a 1/20 chance that the pinata breaks, this causes SIGUSR2 to be sent back to the sender.

Hint: This code might be useful:

int isBroken = (rand() % 20) == 19;

int signalToSend = (isBroken ? SIGUSR2 : SIGUSR1);

Upon receipt of SIGINT the program should do:

printf("Pinata stopping\n");

fflush(stdout);

and end.

Your pinata program must:

A. In main(), do:

A. srand(getpid()); // This seeds the random number generator


B. Install a signal handler for SIGINT that causes the program to end. This signal handler should printf() a message that the pinata process is ending.

C. Install a signal handler for SIGUSR1. The signal handler should see if the pinata broke by computing (rand() % 20) == 19.

§ If it is true then the pinata did break and SIGUSR2 should be sent back to the sender.

§ If it is false then the pinata survived and SIGUSR1 should be sent back to the sender.

D. While the pinata is waiting to be signal()-ed it should not be doing much of anything. It should run code like:

E. while  (shouldRun)

F.   sleep(1);

1. child.c

The child's job is to wait for signal numbered SIGUSR1 from its parent (the gameOfficial) This means it is its turn.

Then the child sends the signal SIGUSR1 to the pinata process.

If the child receives SIGUSR1 (from the pinata) that means it did not bust the pinata. It printf()-s a message of disappointment, and sends SIGUSR1 to its parent say that it has not yet won.

If the child receives SIGUSR2 (from the pinata) that means it did bust the pinata. It printf()-s a boastful message, and sends SIGUSR2 to its parent say that it has won.

Your child program must:

A. In main(), do:

B. srand(getpid()); // This seeds the random number generator


C. Check that there are 3 arguments total on the command line (the program's name and 2 others). If there are not then do:

D. fprintf(stderr,"Usage: %s

E. argv[0]

F.        );

G. exit(EXIT_FAILURE);

H. Install a signal handler for signal SIGINT to be told when to quit. This signal handler should printf() a message that the child process is ending and actually stop the program.

I. Install a signal handler for signal SIGUSR1.

§ If this signal comes from its parent then it should printf() a message that acknowledges that it is its turn and it should send SIGUSR1 to the pinata.

§ If this signal comes from the pinata process then it should printf() a message of disappointment and send signal SIGUSR1 to its parent (the gameOfficial).

J. Install signal handlers for signal SIGUSR2. This handler should printf() a boastful message and send signal SIGUSR2 to its parent (the gameOfficial).

K. While the child is waiting to be signal()-ed it should not be doing much of anything. It should run code like:

L. while  (shouldRun)

M.   sleep(1);

2. gameOfficial.c

The gameOfficial's job is to ask for the number of children, launch the pinata process, launch the desired number of children, and then regulate the game.

After one of the children has reported that it has won then it should send SIGINT to the pinata and all children processes. It should also reap them with waitpid().

Your gameOfficial program must:

A. In a loop get a valid number for numChildren (greater than 0).

B. Install a SIGCHLD signal handler. This handler should have a while loop that does a non-hanging waitpid() that detects whether or not a child process (including pinata process) has ended. If it has it should print that process's PID and whether or not it ended successfully or crashed.

C. Install SIGUSR1 signal handler turnOver(). This function tells the gameOfficial that the current child has finished its turn, but that the game has not yet finished.

D. Install SIGUSR2 signal handler turnOverStopGame(). This function tells the gameOfficial both that the current child has finished its turn and that the game has finished.

E. Have a loop that regulates which child's turn it is. The loop sends SIGUSR1 to the current child.

F. After the above loop, have code that sends SIGINT to all child processes (including the pinata process)

I have written much of the gameOfficial program for you. All you have to do is fill in the juicy bits.

gameOfficial.c


/*--------------------------------------------------------------------------*
*----         ----*
*----  gameOfficial.c      ----*
*----         ----*
*----     This program controls version 2.0 of the pinata-whacking ----*
*---- simulator.       ----*
*----         ----*
*---- ---- ---- ---- ---- ---- ---- ---- ---- ----*
*----         ----*
*---- Version 2.0  2017 September 27 Joseph Phillips ----*
*----         ----*
*--------------------------------------------------------------------------*/

/*----*
*----*  Common include sequence:
*----*/
#include #include #include #include #include #include

/*----*
*----*  Declaration of constants:
*----*/
#define  LINE_LEN  16
#define  PINATA_PROG_NAME "pinata"
#define  CHILD_PROG_NAME  "child"


/*----*
*----*  Definition of global vars:
*----*/
int  shouldRun  = 1;
int  isWaitingForTurn;
pid_t*  childPidArray;
pid_t  pinataPid;


/*----*
*----*  Definition of global fncs:
*----*/

/*  PURPOSE:  To change the global state so that the program knows both that
* the current child process has finished its turn, and that it the game
* is over (that child won).  Ignores parameters.  No return value.
*/
void turnOverStopGame
(int  sig,
siginfo_t* info,
void*  data
)
{
shouldRun  = 0;
isWaitingForTurn = 0;
}


/*  PURPOSE:  To change the global state so that the program knows that the
* current child process has finished its turn, but that it the game is
* not yet over (that child lost).  Ignores parameters.  No return value.
*/
void turnOver(int  sig,
siginfo_t* info,
void*  data
)
{
isWaitingForTurn = 0;
}


/*  PURPOSE:  To reap all child processes that have already finished.  Ignores
* parameters.  No return value.
*/
void child (int  sig,
siginfo_t* info,
void*  data
)
{
int status;
pid_t finishedId;

// YOUR CODE HERE
}



/*  PURPOSE:  To simulate the pinata-whacking game.  Ignores command line
* parameters.  Returns EXIT_SUCCESS to OS on success or EXIT_FAILURE
* otherwise.
*/
int main ()
{
//  I.  Application validity check:

//  II.  Do simulation:
//  II.A.  Get simulation parameters:
int  numChildren;
char  line[LINE_LEN];

//  II.A.1.  Get 'numChildren' (must be greater than or equal to 1):
// YOUR CODE HERE


//  II.B.  Prepare game:
//  II.B.1.  Initialize 'childPidArray':
childPidArray       = (pid_t*)calloc(numChildren,sizeof(pid_t));

//  II.B.2.  Install signal handlers:
struct sigaction sa;

// YOUR CODE HERE

//  II.C.  Launch child processes:
//  II.C.1.  Launch pinata process:
pinataPid = /* REPLACE THIS ZERO -> */ 0;

if  (pinataPid == -1)
{
fprintf(stderr,"Your OS is being fork()-bombed! :(\n");
exit(EXIT_FAILURE);
}

if  (pinataPid == 0)
{
// YOUR CODE HERE TO LAUNCH PINATA_PROG_NAME
fprintf(stderr,"Could not find program %s! :(\n",PINATA_PROG_NAME);
exit(EXIT_FAILURE);
}

//  II.C.2.  Launch pinata-whacking child process(es):
int i;

for  (i = 0;  i < numChildren; i++) { childPidArray[i] = /* REPLACE THIS ZERO -> */ 0;

if  (childPidArray[i] == -1)
{
fprintf(stderr,"Your OS is being fork()-bombed! :(\n");
exit(EXIT_FAILURE);
}

if  (childPidArray[i] == 0)
{
char numText[LINE_LEN];

snprintf(line,LINE_LEN,"%d",pinataPid);
snprintf(numText,LINE_LEN,"%d",i);
// YOUR CODE HERE TO LAUNCH CHILD_PROG_NAME WITH 'line' AS THE FIRST ARG AND 'numText' AS THE 2ND ARG
fprintf(stderr,"Could not find program %s! :(\n",CHILD_PROG_NAME);
exit(EXIT_FAILURE);
}

}

//  II.D.  Play game:
//  II.D.1.  Wait a sec' for all child processes to compose themselves:
sleep(1);

//  II.D.2.  Each iteration tells does one turn of one pinata-whacking
//          child process:
int currentChild = 0;

while  (1)
{
printf("Child %d's turn:\n",currentChild);
isWaitingForTurn = 1;
// YOUR CODE HERE TO SEND 'SIGUSR1' TO 'childPidArray[currentChild]'

while  (isWaitingForTurn)
sleep(3);

if  ( !shouldRun )
break;

currentChild++;

if  (currentChild >= numChildren)
currentChild = 0;
}

printf("Child %d won!\n",currentChild);

//  II.E.  Clean up after game:
//  II.E.1.  Tell all processes to end themselves:
for  (currentChild = 0;  currentChild < numChildren; currentChild++) { // YOUR CODE HERE TO SEND 'SIGINT' TO 'childPidArray[currentChild]' sleep(1); } // YOUR CODE HERE TO SEND 'SIGINT' TO 'pinataPid' sleep(1); // II.E.2. Clean up memory: free(childPidArray); // III. Finished: return(EXIT_SUCCESS); } Communication protocol ple: gameOfficial | | pinata +--(fork/execl)------------------------>>+ (gameOfficial makes the pinata)
|                                        |
|                        child1          |
+--(fork/execl)---------->>+             | (gameOfficial makes child1)
|                          |             |
|              child2      |             |
+--(fork/execl)>>+         |             | (gameOfficial makes child2)
|                |         |             |
|                |         |             |
|                |         |             |
|                |         |             |
|                |         |             |
|                |         |             |
|                |         |             |
+--(SIGUSR1)-----|------->>+             | Control to Child1: "Your turn"
|                |         |             |
|                |         +-(SIGUSR1)->>+ Child1 to Pinata: "Whack!"
|                |         |             |
|                |         +-<<(SIGUSR1)-+ Pinata to Child1: "I survived" | | | | +<>+         |             | Control to Child2: "Your turn"
|                |         |             |
|                +---------|-(SIGUSR1)->>+ Child2 to Pinata: "Whack!"
|                |         |             |
|                +---------|-<<(SIGUSR1)-+ Pinata to Child1: "I survived" | | | | +<>+             | Control to Child1: "Your turn"
|                |         |             |
|                |         +-(SIGUSR1)->>+ Child1 to Pinata: "Whack!"
|                |         |             |
|                |         +-<<(SIGUSR1)-+ Pinata to Child1: "I survived" | | | | +<>+         |             | Control to Child2: "Your turn"
|                |         |             |
|                +---------|-(SIGUSR1)->>+ Child2 to Pinata: "Whack!"
|                |         |             |
|                +---------|-<<(SIGUSR2)-+ Pinata to Child1: "You broke me!" | | | | +<>+ Control to Pinata "Time to stop"
|                |         |             |
|                |         |       (process ends)
|                |         |
+--(SIGINT)------|------->>+               Control to Child1 "Time to stop"
|                |         |
|                |    (process ends)
|                |
+--(SIGINT)---->>+                         Control to Child2 "Time to stop"
|                |
|          (process ends)
|
(process ends)
Sample output:
$ ./gameOfficial
Number of children? 2
Child 0's turn:
Child 0: I'm going to whack at it!
Child 0: A swing and a miss!
Child 1's turn:
Child 1: I'm going to whack at it!
Child 1: Curses!  I think I just weakened it for the next child!
Child 0's turn:
Child 0: I'm going to whack at it!
Child 0: Curses!  I think I just weakened it for the next child!
Child 1's turn:
Child 1: I'm going to whack at it!
Child 1: Damn, I missed the pinata completely!
Child 0's turn:
Child 0: I'm going to whack at it!
Child 0: A swing and a miss!
Child 1's turn:
Child 1: I'm going to whack at it!
Child 1: A swing and a miss!
Child 0's turn:
Child 0: I'm going to whack at it!
Child 0: Hey I hit it!  What's that thing made of?  Kevlar?
Child 1's turn:
Child 1: I'm going to whack at it!
Child 1: Curses!  I think I just weakened it for the next child!
Child 0's turn:
Child 0: I'm going to whack at it!
Child 0: A swing and a miss!
Child 1's turn:
Child 1: I'm going to whack at it!
Oh yeah!  All that candy is MINE baby!
Child 1 won!
Child 0 stopping
4405 has finished.
Child 1 stopping
4406 has finished.
Pinata stopping
4404 has finished.


在线提交订单