C programming with pthreads

lazy808
A3.docx

A3. You are required to make the following changes to the program

"alarm_mutex.c" (alarm_mutex.c can be found at the end of this document) to produce a program named “New_Alarm_Mutex.c”.

There are 2 different types of threads in “New_Alarm_Mutex.c”:

(a) A Main Thread;

(b) Display Alarm Threads.

A3.1 Four types of “Alarm requests” in “New_Alarm_Mutex.c”

Four types of “Alarm requests”: “Start_Alarm”, “Change_Alarm”, “Cancel_Alarm” and

“View_Alarms“requests, are recognized and handled by “New_Alarm_Mutex.c”, as

follows:

(a) “Start_Alarm” requests with the following format:

Alarm> Start_Alarm(Alarm_ID): Time Message

- “Start_Alarm” is a keyword.

- “Alarm_ID” is a positive integer.

- “Time” has the same meaning and syntax as in the program “alarm_mutex.c”.

- “Message” has the same meaning and syntax as in the program “alarm_mutex.c”.

For example:

Alarm> Start_Alarm(2345): 50 Will meet you at Grandma’s house at 6 pm

(b) “Change_Alarm” requests with the following format:

Alarm> Change_Alarm(Alarm_ID): Time Message

- “Change_Alarm” is a keyword.

- “Alarm_ID” is a positive integer.

- “Time” has the same meaning and syntax as in the program “alarm_mutex.c”.

- “Message” has the same meaning and syntax as in the program “alarm_mutex.c”.

For example:

Alarm> Change_Alarm(2345): 80 Will meet you at Grandma’s house later at 8 pm

(c) “Cancel_Alarm” requests with the following format:

Alarm> Cancel_Alarm(Alarm_ID): Time Message

- “Cancel_Alarm” is a keyword.

- “Alarm_ID” is a positive integer.

For example:

Alarm> Cancel_Alarm(2345)

(d) “View_Alarms” requests with the following format:

Alarm> View_Alarms

- “View_Alarms” is a keyword.

For example:

Alarm> View_Alarms

If the user types in something other than one of the above four types of valid alarm

requests, then an error message will be displayed, and the invalid request will be

discarded.

A3.2. The Main Thread in “New_Alarm_Mutex.c”

The main thread in “New_Alarm_Mutex.c” will first determine whether the format of

each alarm request is consistent with the formats specified above; otherwise the alarm

request will be rejected with an error message. If a Message exceeds 128 characters, it

will be truncated to 128 characters.

A3.2.1. For each Start_Alarm request received, the main thread will insert the

corresponding alarm with the specified Alarm_ID into the alarm list, in which all the

alarms are placed in the order of their Alarm_IDs. Then the main thread will print:

“Alarm( <alarm_id>) Inserted Into Alarm List at <insert_time>: <time message>”.

For each newly inserted alarm in the alarm list, the main thread will do the following:

If either:

(a) the number of existing display alarm threads is 0, or

(b) all of the existing display alarm threads have already assigned to each

one of themselves a maximum number of 2 alarms (see A3.3.1 below),

Then create a new display alarm thread.

Then the main thread will print:

“New Display Alarm Thread <thread-id> Created at <create_time>: <time message>”.

Note that above, and in each of the messages printed by the various threads below,

<thread-id> is the thread identifier>; <insert_time>, <create_time>, <assign_time>,

<cancel_time”, <view_time>, <remove_time>, <change_time>, <display_change_time>,

<exit_time>, <print_time>, etc., are the actual times at which the corresponding action

was performed by each thread; those times are all expressed as the number of seconds

from the Unix Epoch Jan 1 1970 00:00; <time message> correspond to “Time” and

“Message” as specified in A3.1 (a), (b) above.

A3.2.2. For each Change_Alarm request received, the main thread will use the

specified Time and Message values in the Change_Alarm request to replace the Time and

Message values in the alarm with the specified Alarm_Id in the alarm list. Then the main

thread will print:

Alarm(<alarm_id>) Changed at <change_time>: <time message>”.

A3.2.3. For each Cancel_Alarm request received, the main thread will remove the

alarm with the specified Alarm_Id from the alarm list; then the main thread will print:

Alarm(<alarm_id>) Canceled at <cancel_time>: <time message>”.

A3.2.4. For each View_Alarms request received, the main thread will print out the

following:

- A list of all the current existing display alarm threads, together with the alarms that each

display alarm thread has assigned to itself, in the following format:

“View Alarms at <view_time>: <time>:

1. Display Thread <thread-id> Assigned:

1a. Alarm(<alarm_id>): Created at <create_time> Assigned at <assign_time> <time

message>

1b. Alarm(<alarm_id>): Created at <create_time> Assigned at <assign_time> <time

message>. (if a second alarm is assigned)

2. Display Thread <thread-id> Assigned:

2a. Alarm(<alarm_id>): Created at <create_time> Assigned at <assign_time> <time

message>

2b. Alarm(<alarm_id>): Created at <create_time> Assigned at <assign_time> <time

message>. (if a second alarm is assigned)

…”

A3.3. The Display Alarm Threads in “New_Alarm_Mutex.c”

After each display alarm thread in “New_Alarm_Mutex.c” has been created by the main

thread, it will do the following:

A3.3.1. For each display alarm thread that has not yet assigned to itself a maximum

of 2 alarms, whenever there exists any new alarm in the alarm list that has not been

assigned to any display alarm thread, each display alarm thread will attempt to assign that

alarm to itself. If a display alarm thread succeeds in assigning an alarm to itself, it will

print:

“Display Thread <thread-id> Assigned Alarm(<alarm_id>) at <assign_time>: <time

message>”.

A3.3.2. For each alarm in the alarm list that has been assigned to this display alarm

thread, if the expiry time of that alarm has been reached, or if that alarm has been

canceled, then the display alarm thread will remove that alarm from the alarm list,

and the display alarm thread will stop printing the message in that alarm Then the

display alarm thread will print:

“Display Alarm Thread <thread-id> Removed Alarm( <alarm_id> at <remove_time>:

<time message>”.

A3.3.3. For each alarm in the alarm list that has been assigned to this display alarm

thread, if the expiry time of that alarm has been reached, or if that alarm has been

canceled and the display alarm thread does not have any more alarms assigned to it,

then the display alarm thread will first print:

“Display Alarm Thread <thread-id> Exiting at <exit_time>”;

Then the display alarm thread will exit from the system.

A3.3.4. For each alarm that has been assigned to this display alarm thread, the display

alarm thread will periodically print, every 5 seconds, the following:

“Alarm (<alarm_id>) Printed by Alarm Display Thread <thread-id>at <print_time>:

<time message> ”.

A3.3.4. For each newly changed alarm in the alarm list, the display alarm thread that

assigned to itself that alarm will start periodically printing, every 5 seconds, the new

message in that newly changed alarm. When the display alarm thread first starts printing

a new changed message it will print:

“Display Thread <thread-id> Starts to Print Changed Message at

<display_change_time>: <time message>”.

B. Platform on Which The Programs Are to be Implemented

The programs should to be implemented using the ANSI C programming language and using linux

**Pls kindly include detailed comments

The alarm_mutex.c file is here:

/*

* alarm_mutex.c

*

* This is an enhancement to the alarm_thread.c program, which

* created an "alarm thread" for each alarm command. This new

* version uses a single alarm thread, which reads the next

* entry in a list. The main thread places new requests onto the

* list, in order of absolute expiration time. The list is

* protected by a mutex, and the alarm thread sleeps for at

* least 1 second, each iteration, to ensure that the main

* thread can lock the mutex to add new work to the list.

*/

#include <pthread.h>

#include <time.h>

#include "errors.h"

/*

* The "alarm" structure now contains the time_t (time since the

* Epoch, in seconds) for each alarm, so that they can be

* sorted. Storing the requested number of seconds would not be

* enough, since the "alarm thread" cannot tell how long it has

* been on the list.

*/

typedef struct alarm_tag {

struct alarm_tag *link;

int seconds;

time_t time; /* seconds from EPOCH */

char message[64];

} alarm_t;

pthread_mutex_t alarm_mutex = PTHREAD_MUTEX_INITIALIZER;

alarm_t *alarm_list = NULL;

/*

* The alarm thread's start routine.

*/

void *alarm_thread (void *arg)

{

alarm_t *alarm;

int sleep_time;

time_t now;

int status;

/*

* Loop forever, processing commands. The alarm thread will

* be disintegrated when the process exits.

*/

while (1) {

status = pthread_mutex_lock (&alarm_mutex);

if (status != 0)

err_abort (status, "Lock mutex");

alarm = alarm_list;

/*

* If the alarm list is empty, wait for one second. This

* allows the main thread to run, and read another

* command. If the list is not empty, remove the first

* item. Compute the number of seconds to wait -- if the

* result is less than 0 (the time has passed), then set

* the sleep_time to 0.

*/

if (alarm == NULL)

sleep_time = 1;

else {

alarm_list = alarm->link;

now = time (NULL);

if (alarm->time <= now)

sleep_time = 0;

else

sleep_time = alarm->time - now;

#ifdef DEBUG

printf ("[waiting: %d(%d)\"%s\"]\n", alarm->time,

sleep_time, alarm->message);

#endif

}

/*

* Unlock the mutex before waiting, so that the main

* thread can lock it to insert a new alarm request. If

* the sleep_time is 0, then call sched_yield, giving

* the main thread a chance to run if it has been

* readied by user input, without delaying the message

* if there's no input.

*/

status = pthread_mutex_unlock (&alarm_mutex);

if (status != 0)

err_abort (status, "Unlock mutex");

if (sleep_time > 0)

sleep (sleep_time);

else

sched_yield ();

/*

* If a timer expired, print the message and free the

* structure.

*/

if (alarm != NULL) {

printf ("(%d) %s\n", alarm->seconds, alarm->message);

free (alarm);

}

}

}

int main (int argc, char *argv[])

{

int status;

char line[128];

alarm_t *alarm, **last, *next;

pthread_t thread;

status = pthread_create (

&thread, NULL, alarm_thread, NULL);

if (status != 0)

err_abort (status, "Create alarm thread");

while (1) {

printf ("alarm> ");

if (fgets (line, sizeof (line), stdin) == NULL) exit (0);

if (strlen (line) <= 1) continue;

alarm = (alarm_t*)malloc (sizeof (alarm_t));

if (alarm == NULL)

errno_abort ("Allocate alarm");

/*

* Parse input line into seconds (%d) and a message

* (%64[^\n]), consisting of up to 64 characters

* separated from the seconds by whitespace.

*/

if (sscanf (line, "%d %64[^\n]",

&alarm->seconds, alarm->message) < 2) {

fprintf (stderr, "Bad command\n");

free (alarm);

} else {

status = pthread_mutex_lock (&alarm_mutex);

if (status != 0)

err_abort (status, "Lock mutex");

alarm->time = time (NULL) + alarm->seconds;

/*

* Insert the new alarm into the list of alarms,

* sorted by expiration time.

*/

last = &alarm_list;

next = *last;

while (next != NULL) {

if (next->time >= alarm->time) {

alarm->link = next;

*last = alarm;

break;

}

last = &next->link;

next = next->link;

}

/*

* If we reached the end of the list, insert the new

* alarm there. ("next" is NULL, and "last" points

* to the link field of the last item, or to the

* list header).

*/

if (next == NULL) {

*last = alarm;

alarm->link = NULL;

}

#ifdef DEBUG

printf ("[list: ");

for (next = alarm_list; next != NULL; next = next->link)

printf ("%d(%d)[\"%s\"] ", next->time,

next->time - time (NULL), next->message);

printf ("]\n");

#endif

status = pthread_mutex_unlock (&alarm_mutex);

if (status != 0)

err_abort (status, "Unlock mutex");

}

}

}