A5 CS343

To fix from a4 (stupid mistakes):

  • Test invalid command-line arguments: “6a” (fix it!)
  • If seed not specified dont run set_seed(seed) I commented it out
  • Use convert() instead of stoi() which fixes 6a invalid command-line. Please shoot me
  • Don’t output if nothing to output deleted it in flushbuffer()

EXT:

Each _Accept defines what cooperation must occur for the accepting task to proceed.

INT:

similar to sem (from previous assignment)

For INT, we use a Condition Variable, which is owned by the mutex object that performs the first wait on it.

INTB:

#include "q2tallyVotes.h"
#include "q2printer.h"
#include <iostream>
 
using namespace std;
 
// constructor for TallyVotes
TallyVotes::TallyVotes( unsigned int voters, unsigned int group, Printer & printer )
    : servingSize( group ), voters( voters ), group( group ), printer( printer ) {}
 
void TallyVotes::wait() {
	bench.wait();							// wait until signalled
	while ( rand() % 2 == 0 ) {				// multiple bargers allowed
		try {
			_Accept( vote || done ) {		// accept barging callers
			} _Else {						// do not wait if no callers
			} // _Accept
		} catch( uMutexFailure::RendezvousFailure & ) {}
	} // while
}
 
void TallyVotes::signalAll() {				// also useful
	while ( ! bench.empty() ) bench.signal(); // drain the condition
}
 
// vote routine for each voter
TallyVotes::Tour TallyVotes::vote( unsigned int id, Ballot ballot ) {
    VOTER_ENTER( group );
 
    if (voters < group) {
        // VOTER_LEAVE( group );
        _Throw Failed();
    }
 
    unsigned int currTicket = ticket;
    ticket++;
 
    if (currTicket >= servingSize) {
        bargers++;
        while (currTicket >= servingSize) {
            PRINT(printer.print( id, Voter::States::Barging, bargers, currGroup ));
            wait();
 
            if (voters < group) {
                bargers--;
                // signalAll();
                // VOTER_LEAVE( group );
                _Throw Failed();
            }
        }
        bargers--;
    }
 
    PRINT(printer.print( id, Voter::States::Vote, ballot ));
    pictureVotes += ballot.picture;
    statueVotes += ballot.statue;
    giftshopVotes += ballot.giftshop;
 
    waiters++;
 
    if (waiters != group) {
        PRINT(printer.print( id, Voter::States::Block, waiters ));
        wait();
        waiters--;
        PRINT(printer.print( id, Voter::States::Unblock, waiters ));
    }
    else {
        tallyAllVotes();
        goingOnTour = true;
        signalAll();
        waiters--;
        PRINT(printer.print( id, Voter::States::Complete, currTour ));
        goingOnTour = false;
    }
 
    if (!goingOnTour && voters < group) {
        // signalAll();
        // VOTER_LEAVE( group );
        _Throw Failed();
    }
 
    if (waiters == 0) {
        servingSize += group;
        signalAll();
    }
 
    VOTER_LEAVE( group );
    return currTour;
}
 
// signify that a voter is done
void TallyVotes::done() {
    voters--;
    if (!goingOnTour && voters < group) {
        signalAll();
    }
}

Correct version:

#include "q2tallyVotes.h"
#include "q2printer.h"
#include <iostream>
 
using namespace std;
 
// constructor for TallyVotes
TallyVotes::TallyVotes( unsigned int voters, unsigned int group, Printer & printer )
    : servingSize( group ), voters( voters ), group( group ), printer( printer ) {}
 
void TallyVotes::wait() {
	bench.wait();							// wait until signalled
	while ( rand() % 2 == 0 ) {				// multiple bargers allowed
		try {
			_Accept( vote || done ) {		// accept barging callers
			} _Else {						// do not wait if no callers
			} // _Accept
		} catch( uMutexFailure::RendezvousFailure & ) {}
	} // while
}
 
void TallyVotes::signalAll() {				// also useful
	while ( ! bench.empty() ) bench.signal(); // drain the condition
}
 
// vote routine for each voter
TallyVotes::Tour TallyVotes::vote( unsigned int id, Ballot ballot ) {
    VOTER_ENTER( group );
 
    if (voters < group) {
        // VOTER_LEAVE( group );
        _Throw Failed();
    }
 
    unsigned int currTicket = ticket;
    ticket++;
 
    if (currTicket >= servingSize) {
        bargers++;
        while (currTicket >= servingSize) {
            PRINT(printer.print( id, Voter::States::Barging, bargers, currGroup ));
            wait();
 
            if (!goingOnTour && voters < group) {
                bargers--;
                // signalAll();
                // VOTER_LEAVE( group );
                _Throw Failed();
            }
        }
        bargers--;
    }
 
    PRINT(printer.print( id, Voter::States::Vote, ballot ));
    pictureVotes += ballot.picture;
    statueVotes += ballot.statue;
    giftshopVotes += ballot.giftshop;
 
    waiters++;
 
    if (waiters != group) {
        PRINT(printer.print( id, Voter::States::Block, waiters ));
        wait();
        waiters--;
        PRINT(printer.print( id, Voter::States::Unblock, waiters ));
    }
    else {
        tallyAllVotes();
        goingOnTour = true;
        signalAll();
        waiters--;
        PRINT(printer.print( id, Voter::States::Complete, currTour ));
        // goingOnTour = true;
    }
 
    goingOnTour = waiters > 0;
 
    if (!goingOnTour && voters < group) {
        // signalAll();
        // VOTER_LEAVE( group );
        _Throw Failed();
    }
 
    if (waiters == 0) {
        servingSize += group;
        signalAll();
    }
 
    VOTER_LEAVE( group );
    return currTour;
}
 
// signify that a voter is done
void TallyVotes::done() {
    voters--;
    if (voters < group) {
        signalAll();
    }
}

For INTB, we use a Condition Variable, which is owned by the mutex object that performs the first wait on it.

AUTO

#include "q2tallyVotes.h"   
#include "q2printer.h"
#include <iostream>
 
using namespace std;
 
// constructor for TallyVotes
TallyVotes::TallyVotes( unsigned int voters, unsigned int group, Printer & printer )
    : voters( voters ), group( group ), printer( printer ) {}
 
// vote routine for each voter
TallyVotes::Tour TallyVotes::vote( unsigned int id, Ballot ballot ) {
    if (voters < group) {
        EXIT();
        _Throw Failed();
    }
 
    PRINT(printer.print( id, Voter::States::Vote, ballot ));
    pictureVotes += ballot.picture;
    statueVotes += ballot.statue;
    giftshopVotes += ballot.giftshop;
 
    waiters++;
 
    if (waiters != group) {
        WAITUNTIL(goingOnTour, PRINT(printer.print( id, Voter::States::Block, waiters )), PRINT(printer.print( id, Voter::States::Unblock, waiters - 1 )));
        if (voters < group) {
            waiters--;
            EXIT();
            _Throw Failed();
        }
    } 
    else {
        tallyAllVotes();
        PRINT(printer.print( id, Voter::States::Complete, currTour ));
        goingOnTour = true;
    }
 
    waiters--;
    goingOnTour = waiters > 0;
    EXIT();
    return currTour;
}
 
// signify that a voter is done
void TallyVotes::done() {
    voters--;
    goingOnTour = (voters < group);
    EXIT();
}

AutomaticSignal.h:

#ifndef AUTOMATIC_SIGNAL_H
#define AUTOMATIC_SIGNAL_H
#define AUTOMATIC_SIGNAL \
struct Node: public uSeqable { \
	uCondition condition; \
}; \
 
uSequence<Node> waiting; \
Node* cursor; \
 
#define WAITUNTIL( pred, before, after ) \
 
if (!waiting.empty() || !pred) { \
	cursor = waiting.head(); \
	Node curr; \
	waiting.addTail(&curr); \
	for ( ;; ) { \
		if (cursor != nullptr) cursor->condition.signal(); \
		before; \
		curr.condition.wait(); \
		after; \
		if (pred) break; \
		cursor = waiting.succ(&curr); \
	} \
	waiting.remove(&curr); \
} \
 
#define EXIT() \
if (!waiting.empty()) { \
	cursor = waiting.head(); \
	cursor->condition.signal(); \
} \
 
#endif // AUTOMATIC_SIGNAL

TASK