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 ofstoi()
→ 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
…