// CSC_4730 | P6 | Methods | Caleb Collar & Kai Kuebler | 10.29.21 #include "MutexSpit.hpp" // Default constructor, create, fill, & shuffle the deck. template <typename T> Spit<T>::Spit(uint64_t sz, uint64_t seed, uint32_t nthreads) { size = sz; numPlayers = nthreads; deck.resize(size); //Fill the deck. for (uint32_t i = 0; i < size; i++) { deck.at(i) = i; } shuffle(deck.begin(), deck.end(), default_random_engine(seed)); //Shuffle the 'deck'. } // Overloaded constructor, take in predefined deck. template <typename T> Spit<T>::Spit(vector<T> &deck, uint32_t nthreads) { size = deck.size(); numPlayers = nthreads; this->deck = deck; } // Player's worker 'action' compares items in subDeck 'hand' to item in critical // section. Will place item 'on' the pile by creating a lock. Will join other // threads when the 'hand' is empty. template <typename T> void Spit<T>::action(vector<T> subDeck, uint32_t tid) { uint64_t workerSpit = 0; while (subDeck.size() > workerSpit) { for (auto i : subDeck) { if (i == pile) { lock_guard<mutex> lock(m); workerSpit++; cout << "Thread:" << setw(5) << right << tid << " " << "hit on:" << setw(10) << right << pile << endl; pile++; } } } } // Method to start the players and the 'game'. template <typename T> void Spit<T>::PlayGame() { players.resize(numPlayers); for (uint32_t i = 0; i < numPlayers; i++) { vector<T> subDeck = i != numPlayers - 1 ? vector<T>{deck.begin() + (i * (deck.size() / numPlayers)), deck.begin() + (i + 1) * (deck.size() / numPlayers)} : vector<T>{deck.begin() + (i * (deck.size() / numPlayers)), deck.end()}; players.at(i) = thread(&Spit<T>::action, this, subDeck, i); } } // Destructor, if there are players in the game - will join them with the other // threads. template <typename T> Spit<T>::~Spit() { if (players.size() > 0) { // Here so that join isn't called when the user has instantiated spit - for (auto &it : players) //class, but didn't call PlayGame() before object ran out of scope. it.join(); } }