Description
CECS 326-01 Assignment 1
This assignment is about fork(), exec(), and wait() system calls, and commandline arguments.
Write two C++ programs, to be named parent.cc and child.cc and compiled into executable parent and
child, respectively that, when run, will work as follows:
parent
1. takes in a list of gender-name pairs from the commandline arguments
2. creates as many child processes as there are in the gender-name pairs and passes to each child
process a child number and a gender-name pair
3. waits for all child processes to terminate
4. outputs “All child processes terminated. Parent exits.” And terminates.
child
1. receives a child number and one gender-name pair arguments from parent
2. outputs “Child # x, a boy (or girl), name xxxxxx.”
3. Note: content of output depends on data received from parent
Sample run
To invoke the execution:
>parent girl Nancy boy Mark boy Joseph
parent process does the following:
1. outputs “I have 3 children.” — Note: the number 3 comes from the number of gender-name pairs in
the commandline arguments
2. creates 3 child processes, and have each execute child and passes to it an integer that represents
the child number and one gender-name pair arguments
3. waits for all child processes to terminate, then
4. outputs “All child processes terminated. Parent exits.”
Output from child processes
From first child process:
Child # 1: I am a girl, and my name is Nancy.
From second child process:
Child # 2, I am a boy, and my name is Mark.
From third child process:
Child # 3, I am a boy, and my name is Joseph.
Output from parent process
All chile processes terminated. Parent exits.
Submit on BeachBoard the source programs parent.cc and child.cc, a screenshot that shows successful
compile of both programs as well as a successful run, and a cover page that provides your name, your
student ID, course # and section, assignment #, due date, submission date, and a clear program description
detailing what the programs are about. Format of the cover page should follow the cover page template
posted on BeachBoard. The programs must be properly formatted and adequately commented to enhance
readability and understanding. Detailed documentation on all system calls are especially needed.
CECS 326-01 Assignment 2
When a user launches a program for execution, the OS creates a user process to execute it. Many OS, including Linux, provides the mechanism for a process to create child processes to run concurrently with the parent process which creates them. Linux provides such support with system calls fork and exec. These concurrent processes may need to communicate between them. One way Linux supports interprocess communication is message queue. Using the System V implementation, a message queue must first be acquired from the operating system by calling msgget. Control operations, e.g., remove, can be performed on an existing message queue by calling msgctl. Processes with appropriate permissions may send and/or receive messages via the message queue by calling msgsnd and msgrcv. Please consult the man pages of these system calls for details.
In this assignment you will make use of what you learned about the Linux message queue mechanism in class, and make use of the fork(), exec() and wait() system calls to create child processes and control the child process’ execution. For this assignment you need to write three C++ programs named master.cc (source program file names may have .cpp suffix), sender.cc, and receiver.cc, which should be compiled into executables master, sender, and receiver, respectively. Together they should do the following:
When master executes, it should first output a message to identify itself. It should then acquire a message queue from the kernel, followed by creating two child processes, with one to execute sender and the other to execute receiver, and pass to them the message queue id. The master process should output its process ID, the message queue ID, the process IDs of the sender and receiver processes it has created, then waits for both child processes to terminate. Then master will remove the message queue and then exit.
master should produce the following sequence of output:
Master, PID xxxxx, begins execution
Master acquired a message queue, id xxxxx
Master created a child process with PID xxxxx to execute sender
Master created a child process with PID xxxxx to execute receiver
Master waits for both child processes to terminate
Master received termination signals from both child processes, removed message queue, and terminates
When sender executes, it should first output a message to identify itself, and show the message queue id it obtained from the exec() system call that invokes its execution. It should then prompt user for a line of input, send the input line to receiver via the message queue created by master.
sender should produce the following sequence of output:
Sender, PID xxxxx, begins execution
Sender received message queue id xxxxx through commandline parameter
Sender: Please input your message
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx [this is user input message]
Sender sent message to message queue
Sender terminates
When receiver executes, it should first output a message to identify itself, and show the message queue id it obtained from the exec() system call that invokes its execution. It then retrieves a message from the message queue, and outputs the message on the screen.
receiver should produce the following sequence of output:
Receiver, PID xxxxx, begins execution
Receiver received message queue id xxxxx through commandline parameter
Receiver: Retrieved the following message from message queue
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx [this is message retrieved from message queue]
Receiver terminates
It should be noted that the display of the above three sets of output may interleave.
The program must run successfully on Linux.
Do the following for this assignment:
- Develop three C++ programs (cc, sender.cc, and receiver.cc) as described above. Make sure your programs are properly formatted as well as adequately and clearly commented. Detailed explanations on all system calls are required and must be in your own words. Simply copying those from the man pages are not acceptable.
- Submit on BeachBoard the three C++ programs, a screenshot that shows successful compile of all three programs as well as a successful run, and a cover page that provides your name, your student ID, course # and section, assignment #, due date, submission date, and a clear program description detailing what the programs are about. Format of the cover page should follow the cover page template posted on BeachBoard. The programs must be properly formatted and adequately commented to enhance readability and understanding. Detailed documentation on all system calls are especially needed.
CECS 326-01 Assignment 3
In this assignment you will make use of the POSIX implementation of the Linux shared memory
mechanism, and make use of the fork() and exec() system calls to create child processes and control the
program that a child process is to execute. For this assignment you need to write two C programs named
master.c and slave.c, which should be compiled into executables master and slave, respectively. Together
they should do the following:
When master executes, it should first output a message to identify itself. It should then request to create a
shared memory segment of a certain name xxxxx, followed by creating n child processes, where both
xxxxx and the number n are obtained from the commandline parameters. Each child process is to execute
slave, with its child number (i.e., 1, 2, etc.) and the shared memory segment name xxxxx passed to it from
the exec() system call. The master process should output the number of slaves it has created, and wait for
all of them to terminate. Upon receiving termination signals from all child processes, master then outputs
the content of the shared memory segment filled in by the slaves, removes the shared memory and then
exits.
The following header file that defines a C struct may be used to structure the shared memory segment:
/* myShm.h */
/* Header file to be used with master.c and slave.c
*/
struct CLASS {
int index; // index to next available response slot
int response[10]; // each child writes its child number here
};
Suppose program execution is launched as follows:
./master 3 my_shm_name
master should produce the following sequence of output:
Master begins execution
Master created a shared memory segment named my_shm_name [ my_shm_name is from comandline ]
Master created 3 child processes to execute slave [ The number 3 is from commandline]
Master waits for all child processes to terminate
Master received termination signals from all 3 child processes
Content of shared memory segment filled by child processes:
— content of shared memory — [ Show what child processes wrote ]
Master removed shared memory segment, and is exiting
When a child process executes slave, it should first output a message to identify itself, and show its child
number and the shared memory segment name it obtained from the exec() system call that invokes its
execution. It should then open the existing shared memory segment, acquire access to it, and write its
child number into the next available slot in the shared memory, close the shared memory and terminate.
slave should produce the following sequence of output:
Slave begins execution
I am child number x, received shared memory name my_shm_name
I have written my child number to shared memory
Slave closed access to shared memory and terminates
It should be noted that the display of the above sets of output may interleave.
The program must run successfully on Linux.
Do the following for this assignment:
1. Develop two C programs (master.c, and slave.c) that work as described above. Make sure your
source programs are properly formatted as well as adequately and clearly commented. Detailed
explanations on all system calls are required and must be in your own words. Simply copying
those from the man pages are not acceptable.
2. Submit on BeachBoard the two C programs, a screenshot that shows successful compile of both
programs as well as a successful run, and a cover page that provides your name, your student ID,
course # and section, assignment #, due date, submission date, and a clear program description
detailing what the programs are about. Format of the cover page should follow the cover page
template on BeachBoard. The programs must be properly formatted and adequately commented
to enhance readability and understanding. Detailed documentation on all system calls are
especially needed.
CECS 326-01 Assignment 4
Cooperating processes need to communicate between them. Linux supports shared memory for interprocess communication in two different implementations: POSIX and System V. A System V shared memory segment can be created and controlled using system calls shmget, shmctl, shmat, shmdt, and a C library function memcpy. Please consult the man pages of these system calls for details. This assignment is designed to illustrate a critical problem with processes executing concurrently that try to access shared data.
For this assignment you need to copy the following two C++ programs (named shmp2.cpp and shmc2.cpp) and a header file booking.h into your Linux directory, compile the two programs into shmp2, and shmc2, respectively. Then run shmp2 and observe what happens. Run shmp2 at least 5 times and observe, report the results and explain what may have caused the peculiarities in the outcome. Your observations and explanation should be reported on the cover page, along with the program description.
BE AWARE that blank lines in a Word document may have extra special characters that gnu compilers don’t recognize. Should you encounter errors due to this problem, delete each blank line and put it back while on the Linux text editor.
The program must run successfully on Linux.
Do the following for this assignment:
- Compile cpp and shmc2.cpp into shmp2 and shmc2, respectively, and run shmp2. Document what the programs are designed to do on the cover page.
- Annotate the programs with adequate amount of comments throughout the program to explain what the program does. System calls require especially detailed comments and must be in your own words. Simply copying the text from the man pages are not acceptable.
- Run shmp2 at least 5 times and observe the results. Explain the problems you have observed in these runs and explain what may be causing the peculiar outcomes on the cover page.
- Submit on BeachBoard the annotated cpp and shmc2.cpp, a screenshot that shows successful compile of the two programs as well as results of 5 runs, and a cover page that provides your name, your student ID, course # and section, assignment #, due date, submission date, a clear program description, and your observations & explanation of the run results. Format of the cover page should follow the cover page template on BeachBoard.
- The programs must be properly formatted and adequately commented to enhance readability and understanding.
/* booking.h */
/* Header file to be used with
* shmp2.cpp and shmc2.cpp
*/
struct BUS {
char bus_number[6];
char date[9];
char title[50];
int seats_left;
};
/* shmp2.cpp */
#include “booking.h”
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/wait.h>
#include <unistd.h>
#include <stdlib.h>
#include <iostream>
#include <stdio.h>
#include <memory.h>
using namespace std;
BUS mybus = { “4321”, “11262021”, “Grand Canyon Tour”, 20 };
#define NCHILD 3
int shm_init( void * );
void wait_and_wrap_up( int [], void *, int );
void rpterror( char *, char * );
int main(int argc, char *argv[])
{
int child[NCHILD], i, shmid;
void *shm_ptr;
char ascshmid[10], pname[14];
shmid = shm_init(shm_ptr);
sprintf (ascshmid, “%d”, shmid);
cout << “Bus ” << mybus.bus_number << ” for ”
<< mybus.title << ” on ” << mybus.date << “, ”
<< mybus.seats_left << ” seats available. ” << endl;
cout << “Booking begins: ” << endl << endl;
for (i = 0; i < NCHILD; i++) {
child[i] = fork();
switch (child[i]) {
case -1:
sprintf (pname, “child%d”, i+1);
rpterror ((char *)”fork failed”, pname);
exit(1);
case 0:
sprintf (pname, “shmc%d”, i+1);
execl(“shmc2″, pname, ascshmid, (char *)0);
rpterror ((char *)”execl failed”, pname);
exit (2);
}
}
wait_and_wrap_up (child, shm_ptr, shmid);
}
int shm_init(void *shm_ptr)
{
int shmid;
shmid = shmget(ftok(“.”,’u’), sizeof(BUS), 0600 | IPC_CREAT);
if (shmid == -1) {
perror (“shmget failed”);
exit(3);
}
shm_ptr = shmat(shmid, (void * ) 0, 0);
if (shm_ptr == (void *) -1) {
perror (“shmat failed”);
exit(4);
}
memcpy (shm_ptr, (void *) &mybus, sizeof(BUS) );
return (shmid);
}
void wait_and_wrap_up(int child[], void *shm_ptr, int shmid)
{
int wait_rtn, w, ch_active = NCHILD;
while (ch_active > 0) {
wait_rtn = wait( (int *)0 );
for (w = 0; w < NCHILD; w++)
if (child[w] == wait_rtn) {
ch_active–;
break;
}
}
cout << “Parent removing shm” << endl;
shmdt (shm_ptr);
shmctl (shmid, IPC_RMID, (struct shmid_ds *) 0);
exit (0);
}
void rpterror(char *string, char *pname)
{
char errline[50];
sprintf (errline, “%s %s”, string, pname);
perror (errline);
}
/* shmc2.cpp */
#include “booking.h”
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/wait.h>
#include <unistd.h>
#include <stdlib.h>
#include <iostream>
#include <stdio.h>
#include <memory.h>
using namespace std;
BUS *bus_ptr;
void *memptr;
char *pname;
int shmid, ret;
void rpterror(char *), srand(), perror(), sleep();
void sell_seats();
int main(int argc, char* argv[])
{
if (argc < 2) {
fprintf (stderr, “Usage:, %s shmid\n”, argv[0]);
exit(1);
}
pname = argv[0];
sscanf (argv[1], “%d”, &shmid);
memptr = shmat (shmid, (void *)0, 0);
if (memptr == (char *)-1 ) {
rpterror ((char *)”shmat failed”);
exit(2);
}
bus_ptr = (struct BUS *)memptr;
sell_seats();
ret = shmdt(memptr);
exit(0);
}
void sell_seats()
{
int all_out = 0;
srand ( (unsigned) getpid() );
while ( !all_out) { /* loop to sell all seats */
if (bus_ptr->seats_left > 0) {
sleep ( (unsigned)rand()%2 + 1);
bus_ptr->seats_left–;
sleep ( (unsigned)rand()%5 + 1);
cout << pname << ” SOLD SEAT — ”
<< bus_ptr->seats_left << ” left” << endl;
}
else {
all_out++;
cout << pname << ” sees no seats left” << endl;
}
sleep ( (unsigned)rand()%5 + 1);
}
}
void rpterror(char* string)
{
char errline[50];
sprintf (errline, “%s %s”, string, pname);
perror (errline);
}
CECS 326-01 Assignment 5
As you have come to understand, the shmp2.cpp and shmc2.cpp (or shmp2.c and shmc2.c) you compiled and ran in Assignment 4 have serious deficiency due to race condition. In this assignment you are to correct the problem using one of the semaphore mechanisms that Linux provides. Note that any corrections you make should not include the removal or changes of the sleep() calls in the shmc1 program. Two implementations of semaphore are commonly available on most distributions of UNIX and Linux operating systems: System V and POSIX. In this assignment you will use the POSIX implementation. The POSIX implementation supports named and unnamed semaphores, both of which are defined in . The named semaphore mechanism includes sem_wait(), sem_post(), sem_open(), sem_close() & sem_unlink(), and should be used in this assignment. Details on the definition of these system calls and their use may be found on Linux man pages. The program must run successfully on Linux. Do the following for this assignment: 1. Add necessary synchronization code in your Assignment-4 C/C++ programs to correct problems due to race condition, and compile them into executables shmp2 and shmc2, respectively. Make sure that sufficient and proper comments are included on the added code as well as the existing code. 2. Run your corrected version of shmp2 (with shmc2) to make sure that the output is correct. 3. Submit on BeachBoard the two corrected programs, along with the booking.h file, a screenshot that shows successful compile of both programs as well as a successful run, and a cover page that provides your name, your student ID, course # and section, assignment #, due date, submission date, and a clear program description detailing what you have done for the correction. Format of the cover page should follow the cover page template on BeachBoard. 4. The programs must be properly formatted and adequately commented to enhance readability and understanding. Detailed documentation on all system calls are especially needed. /* booking.h */ /* Header file to be used with * shmp2.cpp and shmc2.cpp */ struct BUS { char bus_number[6]; char date[9]; char title[50]; int seats_left; }; /* shmp2.cpp */ #include “booking.h” #include <sys/types.h> #include <sys/ipc.h> #include <sys/shm.h> #include <sys/wait.h> #include #include #include #include #include using namespace std; BUS mybus = { “4321”, “11262021”, “Grand Canyon Tour”, 20 }; #define NCHILD 3 int shm_init( void * ); void wait_and_wrap_up( int [], void *, int ); void rpterror( char *, char * ); int main(int argc, char *argv[]) { int child[NCHILD], i, shmid; void *shm_ptr; char ascshmid[10], pname[14]; shmid = shm_init(shm_ptr); sprintf (ascshmid, “%d”, shmid); cout << “Bus ” << mybus.bus_number << ” for ” << mybus.title << ” on ” << mybus.date << “, ” << mybus.seats_left << ” seats available. ” << endl; cout << “Booking begins: ” << endl << endl; for (i = 0; i < NCHILD; i++) { child[i] = fork(); switch (child[i]) { case -1: sprintf (pname, “child%d”, i+1); rpterror ((char *)”fork failed”, pname); exit(1); case 0: sprintf (pname, “shmc%d”, i+1); execl(“shmc2″, pname, ascshmid, (char *)0); rpterror ((char *)”execl failed”, pname); exit (2); } } wait_and_wrap_up (child, shm_ptr, shmid); } int shm_init(void *shm_ptr) { int shmid; shmid = shmget(ftok(“.”,’u’), sizeof(BUS), 0600 | IPC_CREAT); if (shmid == -1) { perror (“shmget failed”); exit(3); } shm_ptr = shmat(shmid, (void * ) 0, 0); if (shm_ptr == (void *) -1) { perror (“shmat failed”); exit(4); } memcpy (shm_ptr, (void *) &mybus, sizeof(BUS) ); return (shmid); } void wait_and_wrap_up(int child[], void *shm_ptr, int shmid) { int wait_rtn, w, ch_active = NCHILD; while (ch_active > 0) { wait_rtn = wait( (int *)0 ); for (w = 0; w < NCHILD; w++) if (child[w] == wait_rtn) { ch_active–; break; } } cout << “Parent removing shm” << endl; shmdt (shm_ptr); shmctl (shmid, IPC_RMID, (struct shmid_ds *) 0); exit (0); } void rpterror(char *string, char *pname) { char errline[50]; sprintf (errline, “%s %s”, string, pname); perror (errline); } /* shmc2.cpp */ #include “booking.h” #include <sys/types.h> #include <sys/ipc.h> #include <sys/shm.h> #include <sys/wait.h> #include #include #include #include #include using namespace std; BUS *bus_ptr; void *memptr; char *pname; int shmid, ret; void rpterror(char *), srand(), perror(), sleep(); void sell_seats(); int main(int argc, char* argv[]) { if (argc < 2) { fprintf (stderr, “Usage:, %s shmid\n”, argv[0]); exit(1); } pname = argv[0]; sscanf (argv[1], “%d”, &shmid); memptr = shmat (shmid, (void *)0, 0); if (memptr == (char *)-1 ) { rpterror ((char *)”shmat failed”); exit(2); } bus_ptr = (struct BUS *)memptr; sell_seats(); ret = shmdt(memptr); exit(0); } void sell_seats() { int all_out = 0; srand ( (unsigned) getpid() ); while ( !all_out) { /* loop to sell all seats */ if (bus_ptr->seats_left > 0) { sleep ( (unsigned)rand()%2 + 1); bus_ptr->seats_left–; sleep ( (unsigned)rand()%5 + 1); cout << pname << ” SOLD SEAT — ” << bus_ptr->seats_left << ” left” << endl; } else { all_out++; cout << pname << ” sees no seats left” << endl; } sleep ( (unsigned)rand()%5 + 1); } } void rpterror(char* string) { char errline[50]; sprintf (errline, “%s %s”, string, pname); perror (errline); }
CECS 326-01 Assignment 6
As you have come to understand, the shmp2.cpp and shmc2.cpp (or shmp2.c and shmc2.c) you compiled and ran in Assignment 4 have serious deficiency due to race condition. In Assignment 5 you used the POSIX named semaphore to provide access control to the shared data, thereby correcting the problem by enforcing mutual exclusion. With named semaphores, however, you would need to generate a unique name for every semaphore and associate each name with the shared data you want to control. This approach will become difficult to manage when the number of shared data structures is large. For example, if you have 100 bus tours to manage, you will have to create 100 semaphores, each with a unique name. An alternative is to use the POSIX unnamed semaphores, which can be declared in the same shared memory segment where the tour data are stored. In this assignment, you will have to use a POSIX unnamed semaphore to achieve the necessary access control so that the seat selling results will not show errors. To include the semaphore in the bus tour data structure, the previous booking.h header file has been revised to booking3.h as shown in this document. The two C++ programs have also been revised as shmp3.cpp and shmc3.cpp to match the changes made in booking3.h. Add code as needed to these two programs so that the erroneous outcomes are corrected. The POSIX implementation supports named and unnamed semaphores, both of which are defined in . The unamed semaphore mechanism includes sem_wait(), sem_post(), sem_init(), and sem_destroy(), and should be used in this assignment. Details on the definition of these system calls and their use may be found on Linux man pages. The programs should be compiled using g++ and link with –lpthread. The program must run successfully on Linux. Do the following for this assignment: 1. Add necessary synchronization code in the following C++ programs to correct problems due to race condition, and compile them into executables shmp3 and shmc3, respectively. Make sure that sufficient and proper comments are included on the added code as well as the existing code. 2. Run your corrected version of shmp3 (with shmc3) to make sure that the output is correct. 3. Submit on BeachBoard the two corrected programs, along with the booking3.h file, a screenshot that shows successful compile of both programs as well as a successful run, and a cover page that provides your name, your student ID, course # and section, assignment #, due date, submission date, and a clear program description detailing what you have done for the correction. Format of the cover page should follow the cover page template on BeachBoard. 4. The programs must be properly formatted and adequately commented to enhance readability and understanding. Detailed documentation on all system calls are especially needed. /* booking3.h * Header file to be used with * shmp3.cpp and shmc3.cpp */ #include // header file needed for POSIX semaphore struct TOUR { char bus_number[6]; char date[9]; char title[50]; int seats_left; }; struct BUS { sem_t sem1; // semaphore to control access to tour data below TOUR tour1 = { “4321”, “11262021”, “Grand Canyon Tour”, 20 }; } mybus; /* shmp3.cpp */ #include “booking3.h” #include <sys/types.h> #include <sys/ipc.h> #include <sys/shm.h> #include <sys/wait.h> #include #include #include #include #include using namespace std; #define NCHILD 3 int shm_init( void * ); void wait_and_wrap_up( int [], void *, int ); void rpterror( char *, char * ); int main(int argc, char *argv[]) { int child[NCHILD], i, shmid; void *shm_ptr; char ascshmid[10], pname[14]; shmid = shm_init(shm_ptr); sprintf (ascshmid, “%d”, shmid); cout << “Bus ” << mybus.tour1.bus_number << ” for ” << mybus.tour1.title << ” on ” << mybus.tour1.date << “, ” << mybus.tour1.seats_left << ” seats available. ” << endl; cout << “Booking begins: ” << endl << endl; for (i = 0; i < NCHILD; i++) { child[i] = fork(); switch (child[i]) { case -1: sprintf (pname, “child%d”, i+1); rpterror ((char *)”fork failed”, pname); exit(1); case 0: sprintf (pname, “shmc%d”, i+1); execl(“shmc3″, pname, ascshmid, (char *)0); rpterror ((char *)”execl failed”, pname); exit (2); } } wait_and_wrap_up (child, shm_ptr, shmid); } int shm_init(void *shm_ptr) { int shmid; shmid = shmget(ftok(“.”,’u’), sizeof(BUS), 0600 | IPC_CREAT); if (shmid == -1) { perror (“shmget failed”); exit(3); } shm_ptr = shmat(shmid, (void * ) 0, 0); if (shm_ptr == (void *) -1) { perror (“shmat failed”); exit(4); } memcpy (shm_ptr, (void *) &mybus, sizeof(BUS) ); return (shmid); } void wait_and_wrap_up(int child[], void *shm_ptr, int shmid) { int wait_rtn, w, ch_active = NCHILD; while (ch_active > 0) { wait_rtn = wait( (int *)0 ); for (w = 0; w < NCHILD; w++) if (child[w] == wait_rtn) { ch_active–; break; } } cout << “Parent removing shm” << endl; shmdt (shm_ptr); shmctl (shmid, IPC_RMID, (struct shmid_ds *) 0); exit (0); } void rpterror(char *string, char *pname) { char errline[50]; sprintf (errline, “%s %s”, string, pname); perror (errline); } /* shmc3.cpp */ #include “booking3.h” #include <sys/types.h> #include <sys/ipc.h> #include <sys/shm.h> #include <sys/wait.h> #include #include #include #include #include using namespace std; BUS *bus_ptr; void *memptr; char *pname; int shmid, ret; void rpterror(char *), srand(), perror(), sleep(); void sell_seats(); int main(int argc, char* argv[]) { if (argc < 2) { fprintf (stderr, “Usage:, %s shmid\n”, argv[0]); exit(1); } pname = argv[0]; sscanf (argv[1], “%d”, &shmid); memptr = shmat (shmid, (void *)0, 0); if (memptr == (char *)-1 ) { rpterror ((char *)”shmat failed”); exit(2); } bus_ptr = (struct BUS *)memptr; sell_seats(); ret = shmdt(memptr); exit(0); } void sell_seats() { int all_out = 0; srand ( (unsigned) getpid() ); while ( !all_out) { /* loop to sell all seats */ if (bus_ptr->tour1.seats_left > 0) { sleep ( (unsigned)rand()%2 + 1); bus_ptr->tour1.seats_left–; sleep ( (unsigned)rand()%5 + 1); cout << pname << ” SOLD SEAT — ” << bus_ptr->tour1.seats_left << ” left” << endl; } else { all_out++; cout << pname << ” sees no seats left” << endl; } sleep ( (unsigned)rand()%5 + 1); } } void rpterror(char* string) { char errline[50]; sprintf (errline, “%s %s”, string, pname); perror (errline); }