Demo entry 6722352

demo

   

Submitted by anonymous on Mar 22, 2018 at 23:34
Language: C. Code size: 15.1 kB.

/* 
 * Server Software (COMSM2001), 2017-18, Coursework 1.
 *
 * This is a skeleton program for COMSM2001 (Server Software) coursework 1
 * "the project marking problem". Your task is to synchronise the threads
 * correctly by adding code in the places indicated by comments in the
 * student, marker and run functions.
 * You may create your own global variables and further functions.
 * The code in this skeleton program can be used without citation in the files
 * that you submit for your coursework.
 */

#include <stdlib.h>
#include <stdio.h>
#include <pthread.h>
#include <time.h>
#include <sys/time.h>

/*
 * Parameters of the program. The constraints are D < T and
 * S*K <= M*N.
 */
struct demo_parameters {
    int S;   /* Number of students */
    int M;   /* Number of markers */
    int K;   /* Number of markers per demo */
    int N;   /* Number of demos per marker */
    int T;   /* Length of session (minutes) */
    int D;   /* Length of demo (minutes) */
};

/* Global object holding the demo parameters. */
struct demo_parameters parameters;

/* The demo start time, set in the main function. Do not modify this. */
struct timeval starttime;

/* 
 * You may wish to place some global variables here. 
 * Remember, globals are shared between threads.
 * You can also create functions of your own.
 */
struct markerresourse
{
    int mState;//markers state, 0: idle, 1: grabbed
    int sId; //studentID, grabbed by this student
    int jobs; //how many jobs has this marker done
};
struct markerresourse *markers;// create a global variable for markers information
int *sState;//student state 0: waiting or working, 1: finished

pthread_mutex_t lock;
pthread_cond_t conds;//for markers and students
pthread_cond_t condk;//for students
/*
 * timenow(): returns current simulated time in "minutes" (cs).
 * Assumes that starttime has been set already.
 * This function is safe to call in the student and marker threads as
 * starttime is set in the run() function.
 */
int timenow() {
    struct timeval now;
    gettimeofday(&now, NULL);
    return (now.tv_sec - starttime.tv_sec) * 100 + (now.tv_usec - starttime.tv_usec) / 10000;
}

/* delay(t): delays for t "minutes" (cs) */
void delay(int t) {
    struct timespec rqtp, rmtp;
    t *= 10;
    rqtp.tv_sec = t / 1000;
    rqtp.tv_nsec = 1000000 * (t % 1000);
    nanosleep(&rqtp, &rmtp);
}

/* panic(): simulates a student's panicking activity */
void panic() {
    delay(random() % (parameters.T - parameters.D));
}

/* demo(): simulates a demo activity */
void demo() {
    delay(parameters.D);
}

/*
 * A marker thread. You need to modify this function.
 * The parameter arg is the number of the current marker and the function
 * doesn't need to return any values.
 * Do not modify the printed output as it will be used as part of the testing.
 */
// int checksState(){//check if all students finished
// 	int i;
// 	int index = 0;  //0: all student finished    1: some students are waiting
// 	for(i = 0; i < parameters.S; i++){
// 		if(sState[i] == 0){
// 			index = 1;
// 			break;
// 		}
// 	}
// 	return index;
// }

void *marker(void *arg) {
    int markerID = *(int *)arg;
    
    /*
     * The following variable is used in the printf statements when a marker is
     * grabbed by a student. It shall be set by this function whenever the
     * marker is grabbed - and before the printf statements referencing it are
     * executed.
     */
    int studentID;
    
    /*
     * The following variable shall indicate which job the marker is currently
     * executing, the first being job 0. The variable ranges from 0 to
     * (parameters.N - 1) .
     */
    int job = 0;
    int err;
    /* 1. Enter the lab. */
    printf("%d marker %d: enters lab\n", timenow(), markerID);
    //markers[markerID].mState = 0;//initialise markers resourse.

    /* A marker marks up to N projects. */
    /* 2. Repeat (N times). 
     *    (a) Wait to be grabbed by a student.
     *    (b) Wait for the student's demo to begin
     *        (you may not need to do anything here).
     *    (c) Wait for the demo to finish.
     *        Do not just wait a given time -
     *        let the student signal when the demo is over.
     *    (d) Exit the lab.
     */
    /* 
     * 3. If the end of the session approaches (i.e. there is no time
     *    to start another demo) then the marker waits for the current
     *    demo to finish (if they are currently attending one) and then
     *    exits the lab.
     */
    while(job < parameters.N){ //loop, until N jobs
        err = pthread_mutex_lock(&lock);
        if(err != 0){ abort(); }
        if(job == 0) markers[markerID].mState = 0;
        while(timenow() <= (parameters.T - parameters.D) && markers[markerID].mState == 0){
            err = pthread_cond_broadcast(&condk);//wake up studens who are waitting for idle markers
    		if(err != 0){ abort(); }

            err = pthread_cond_wait(&conds, &lock);//wait to be grabbed
            if(err != 0){ abort(); }
        }

        if(timenow() > (parameters.T - parameters.D)){//check if timeout
                err = pthread_mutex_unlock(&lock);
                if(err != 0){ abort(); }
                printf("%d marker %d: exits lab (timeout)\n", timenow(), markerID);
                pthread_exit(0);
        }

        if(markers[markerID].mState == 1){//check if this marker was grabbed 
            studentID = markers[markerID].sId;//get studentID
            /* The following line shall be printed when a marker is grabbed by a student. */
            printf("%d marker %d: grabbed by student %d (job %d)\n", timenow(), markerID, studentID, job + 1);
        }
        while(sState[studentID] == 0){
            err = pthread_cond_wait(&conds, &lock);//wait until demo finish
            if(err != 0){ abort(); }
        }
	err = pthread_mutex_unlock(&lock);
        if(err != 0){ abort(); }
        if(sState[studentID] == 1){//check if student finish
            /* The following line shall be printed when a marker has finished attending a demo. */
            printf("%d marker %d: finished with student %d (job %d)\n", timenow(), markerID, studentID, job + 1);
            markers[markerID].mState = 0;//release marker
            job++;//finished job ++
        }
        
        markers[markerID].jobs = job;//store this information in the global variable
    }
    /* 
     * When the marker exits the lab, exactly one of the following two lines shall be
     * printed, depending on whether the marker has finished all their jobs or there
     * is no time to complete another demo.
     */
    if(timenow() <= parameters.T){
        printf("%d marker %d: exits lab (finished %d jobs)\n", timenow(), markerID, parameters.N);
    }
    return NULL;
}
int * msSort(int *array, int num){//sort the jobs, so students can grabbed markers with less finished jobs
    int *p;
    p = array;
    int i;
    int j;
    for(i = 0; i < num; i++){
        for(j = 0; j < (num - i - 1); j++){
            if(p[j] > p[j +1]){
                int t = p[j];
                p[j] = p[j + 1];
                p[j + 1] = t;
            }
        }
    }
    return p;
}

void grabKmarkers(int sId){ //grab enough markers 
    int index = 0;
    int idleMarkers = 0;//number of idle markers
    int *p;
    int i;
    for(i = 0; i < parameters.M; i++){
        if(markers[i].mState == 0)
            idleMarkers++;
    }
    p = (int *)malloc(sizeof(int) * idleMarkers);
    int *m = p;
    //get jobs array
    for(i = 0; i < parameters.M; i++){
        if(markers[i].mState == 0){
            *m = markers[i].jobs;
            m++;
        }
    }
    p = msSort(p, idleMarkers);//intend to grab markers with less finished jobs
    while(index < parameters.K){
        for(i = 0; i < parameters.M; i++){
            if(markers[i].mState == 0 && markers[i].jobs <= (parameters.N - 1) && markers[i].jobs == p[index]){
                markers[i].mState = 1;
                markers[i].sId = sId;
                index++;
                break;
            }
        }
    }
}

//release markers, set their state to 0
// void releaseMarkers(int sId){
//     int i;
//     for(i = 0; i < parameters.M; i++){
//         if(markers[i].sId == sId && markers[i].mState == 1){
//             markers[i].mState = 0;
//             markers[i].sId = 0;
//         }
//     }
// }


//check the number of idle markers, 0: enough, 1: not
int checkMarkersNumber(){
    int numberofMarkers = 0;
    int i;
    for(i = 0; i < parameters.M; i++){
        if(markers[i].mState == 0 && markers[i].jobs <= (parameters.N - 1)){
            numberofMarkers++;
        }
    }
    if(numberofMarkers >= parameters.K)
        return 0;//enough
    else return 1;
}
/*
 * A student thread. You must modify this function.
 */
void *student(void *arg) {
    /* The ID of the current student. */
    int studentID = *(int *)arg;

    /* 1. Panic! */
    printf("%d student %d: starts panicking\n", timenow(), studentID);
    panic();

    /* 2. Enter the lab. */
    printf("%d student %d: enters lab\n", timenow(), studentID);
    /* 3. Grab K markers. */
    int err;
    err = pthread_mutex_lock(&lock);
    if(err != 0){ abort(); }
    while(timenow() <= (parameters.T - parameters.D) && checkMarkersNumber() != 0){
        err = pthread_cond_wait(&condk, &lock);//wait if the number of idle markers is not enough
        if(err != 0){ abort(); }
    }

    if(timenow() > (parameters.T - parameters.D)){//check if timeout
        err = pthread_mutex_unlock(&lock);
        if(err != 0){ abort(); }
        printf("%d student %d: exits lab (timeout)\n", timenow(), studentID);
        sState[studentID] = 1;//if timeout, exit and set the state to 1
        pthread_exit(0);
    }

    grabKmarkers(studentID);//grab K markers
    err = pthread_cond_broadcast(&conds);//wake up all markers, markers check if they are grabbed or not
    if(err != 0){ abort(); }
    err = pthread_mutex_unlock(&lock);
    if(err != 0){ abort(); }

    /* 4. Demo! */
    /*
     * If the student succeeds in grabbing K markers and there is enough time left
     * for a demo, the following three lines shall be executed in order.
     * If the student has not started their demo and there is not sufficient time
     * left to do a full demo, the following three lines shall not be executed
     * and the student proceeds to step 5.
     */
    printf("%d student %d: starts demo\n", timenow(), studentID);
    demo();
    printf("%d student %d: ends demo\n", timenow(), studentID);

    err = pthread_mutex_lock(&lock);
    if(err != 0){ abort(); }
    sState[studentID] = 1;//set student state, 1: finished
    err = pthread_cond_broadcast(&conds);//wake up all markers, markers check if demo finished or not
    if(err != 0){ abort(); }
    err = pthread_mutex_unlock(&lock);
    if(err != 0){ abort(); }

    /* 5. Exit the lab. */
    /* 
     * Exactly one of the following two lines shall be printed, depending on
     * whether the student got to give their demo or not.
     */
    printf("%d student %d: exits lab (finished)\n", timenow(), studentID);
    return NULL;
}

/* The function that runs the session.
 * You MAY want to modify this function.
 */
void run() {
    int i;
    int ok;
    int markerID[100], studentID[100];
    pthread_t markerT[100], studentT[100];
    sState = (int *)malloc(sizeof(int) * parameters.S);
    markers = (struct markerresourse*)malloc(sizeof(struct markerresourse) * parameters.M);

    ok = pthread_mutex_init(&lock, NULL);
    if(ok != 0){ abort(); }
    ok = pthread_cond_init(&conds, NULL);
    if(ok != 0){ abort(); }
    ok = pthread_cond_init(&condk, NULL);
    if(ok != 0){ abort(); }

    printf("S=%d M=%d K=%d N=%d T=%d D=%d\n",
        parameters.S,
        parameters.M,
        parameters.K,
        parameters.N,
        parameters.T,
        parameters.D);
    gettimeofday(&starttime, NULL);  /* Save start of simulated time */

    /* Create S student threads */
    for (i = 0; i<parameters.S; i++) {
        studentID[i] = i;
        ok = pthread_create(&studentT[i], NULL, student, &studentID[i]);
         if (ok != 0) { abort(); }
    }
    /* Create M marker threads */
    for (i = 0; i<parameters.M; i++) {
        markerID[i] = i;
        ok = pthread_create(&markerT[i], NULL, marker, &markerID[i]);
         if (ok != 0) { abort(); }
    }

    /* With the threads now started, the session is in full swing ... */
    delay(parameters.T - parameters.D);
    /* 
     * When we reach here, this is the latest time a new demo could start.
     * You might want to do something here or soon after.
     */
    ok = pthread_cond_broadcast(&condk);//students exit(timeout)
    if(ok != 0){ abort(); }
    ok = pthread_cond_broadcast(&conds);//markers exit(timeout)
    if(ok != 0){ abort(); }
    delay(1);
    ok = pthread_cond_broadcast(&conds);//markers exi(timeout)
    if(ok != 0){ abort(); }
	ok = pthread_cond_broadcast(&condk);//students exit(timeout)
    if(ok != 0){ abort(); }

    delay(parameters.D - 1);//markers exit(timeout)
    ok = pthread_cond_broadcast(&conds);
    if(ok != 0){ abort(); }

    /* Wait for student threads to finish */
    for (i = 0; i<parameters.S; i++) {
        ok = pthread_join(studentT[i], NULL);
         if (ok != 0) { abort(); }
    }

    /* Wait for marker threads to finish */
    for (i = 0; i<parameters.M; i++) {
        ok = pthread_join(markerT[i], NULL);
         if (ok != 0) { abort(); }
    }

    //destroy mutexs and condition variables
    ok = pthread_mutex_destroy(&lock);
    if (ok != 0) { abort(); }
    ok = pthread_cond_destroy(&condk);
    if (ok != 0) { abort(); }
    ok = pthread_cond_destroy(&conds);
    if (ok != 0) { abort(); }

}

/*
 * main() checks that the parameters are ok. If they are, the interesting bit
 * is in run() so please don't modify main().
 */
int main(int argc, char *argv[]) {
    if (argc < 6) {
        puts("Usage: demo S M K N T D\n");
        exit(1);
    }
    parameters.S = atoi(argv[1]);
    parameters.M = atoi(argv[2]);
    parameters.K = atoi(argv[3]);
    parameters.N = atoi(argv[4]);
    parameters.T = atoi(argv[5]);
    parameters.D = atoi(argv[6]);
    if (parameters.M > 100 || parameters.S > 100) {
        puts("Maximum 100 markers and 100 students allowed.\n");
        exit(1);
    }
    if (parameters.D >= parameters.T) {
        puts("Constraint D < T violated.\n");
        exit(1);
    }
    if (parameters.S*parameters.K > parameters.M*parameters.N) {
        puts("Constraint S*K <= M*N violated.\n");
        exit(1);
    }

    srand(time(NULL));
    
    // We're good to go.

    run();

    return 0;
}

This snippet took 0.02 seconds to highlight.

Back to the Entry List or Home.

Delete this entry (admin only).