#diverging pthreads logic
61 messages · Page 1 of 1 (latest)
When your question is answered use !solved to mark the question as resolved.
Remember to ask specific questions, provide necessary details, and reduce your question to its simplest form. For tips on how to ask a good question use !howto ask.
my code is as follows:
/*
6 players, 1 of them will be the dealer depending on round
round 1 = player 1 is the dealer
1 deck of cards - vector
dealer draws one card, called target card
dealer give each player 1 card
"dealer places cards on table to draw from" - mutex protected deck
players then take turns in RR (ignoring dealer) pulling 1 card from the deck
if 1 of the players card matches the target card, they win and the round ends
else if neither match, discards 1 card at random (card is placed at the end of the deck), then passes to the next player
when rounds ends next player is the dealer
*/
#include <stdio.h>
#include <iostream>
#include <stdlib.h>
#include <string.h>
//#include <sys/resource.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <pthread.h>
#include <queue>
#include <vector>
#include <algorithm>
#include <ctime>
using namespace std;
vector<int> deck;
vector< vector<int> > playerHands;
volatile int target_card;
volatile int rounds = 0;
// create a mutex
pthread_mutex_t deck_mutex;
pthread_mutex_t turn_mutex;
pthread_mutex_t round_mutex;
pthread_barrier_t barrier;
// Initialize threads
pthread_t* const handle = new pthread_t[6];
static void* game( void* arg );
static void dealer( long my_rank );
static void player( long my_rank );
int main(){
//fill the deck 1-13, face cards are 11, 12, 13
for( int i = 1; i <= 13; i++){
// push 1 value for each suit
deck.push_back( i );
deck.push_back( i );
deck.push_back( i );
deck.push_back( i );
}
// Shuffle the vector
srand(time(NULL));
random_shuffle(deck.begin(), deck.end());
// Print the shuffled deck (for testing purposes)
for (const auto &card : deck) {
cout << card << " ";
}
//initialize players hands vectors
for( int i = 0; i < 6; i++){
// Pushes a epmty vector for each players hand
// locate each player via vector index playerHands[player # - 1]
playerHands.push_back(vector<int>());
}
pthread_mutex_init( &deck_mutex, NULL );
pthread_mutex_init( &turn_mutex, NULL );
pthread_mutex_init( &round_mutex, NULL );
pthread_barrier_init(&barrier, NULL, 6);
for( int i = 0; i < 6; i++ ){
pthread_create(&handle[i], NULL, game, (void*)i);
}
}
static void* game( void* arg ){
const long my_rank = (long)arg;
for( int i = 0; i < 6; i++){
//pick dealer
if( my_rank == rounds ){
dealer( my_rank );
}
//pick players
if( my_rank != rounds ){
player( my_rank );
}
}
return NULL;
}
static void dealer( long my_rank ){
cout << endl << my_rank << endl;
pthread_mutex_lock( &deck_mutex );
//pick a target card from top of deck
target_card = deck.front();
deck.erase(deck.begin());
//deal a card to each players hand
for( int i = 0; rounds < 6; i++ ){
if ( i != rounds ){
playerHands[i].push_back(deck.front());
deck.erase(deck.begin());
}
}
pthread_mutex_unlock(&deck_mutex);
// Players do the rest of the functionality
pthread_barrier_wait(&barrier);
}
static void player( long my_rank ){
// Buffer that will stop all threads until all 6 reach barrier
pthread_barrier_wait(&barrier);
}
why are you using pthreads
we're supposed to simulate the game as if there are actual players. its supposed to be practice using POSIX threads, but we never covered using divergence
we only practiced using parallel programming to supplementary complete a task
my primary concern rn is if i can call pthread_barrier_wait(&barrier); in 2 places and have have them work/release the threads
cuz chatgpt is telling me no, but its pretty innacurate with pthreads, and debugging is also challenging with pthreads
firstly:
you have rounds defined as a volatile int initialized to 0
it never changes
so
if ( i != rounds ){
playerHands[i].push_back(deck.front());
deck.erase(deck.begin());
}
}```
0 is always less than 6
so this'll go on forever
or until i is not a valid index of playerHands, which, in your case, is when it is 7
i still needed to increment rounds when a winner is determined, but im focusing on how to plock player threads until dealer pushes a hard into each of the players hands/ playerhands vector
so you're asking how to block the pthreads until a condition is met?
yeah, cuz the dealer has to deal first, but the dealer() function wont always be called first
but yeah, i see the issue here now
pthread_join is perfect for this
but that reduces all the threads, i would have to launch them all again, which is a strategy but i dont think it solves the issue that the dealer has to act first despite not being called first
if the dealer thread is running once
it doesn't have to be its own thread at all
why not run the dealer function and THEN launch the player threads?
the puzzle about this problem is that each thread will have a turn as the dealer
in that case, what you have currently looks fine
the barrier won't be surpassed until the dealer thread is finished
i want to double check if the way im using barrier is gonna work, cuz in other projects i call barrier wait ina pthread function that all the threads run, this time i got 1 thread in dealer and 5 threads in player, i dont want to cause a deadlock
so im also looking at pthread_cond_wait() to see how to use that
if there's any deadlock, it'll be a result of the pthread source code if you're using pthread_barrier_wait lol
you're writing very c-like c++
what does the variable rounds represent? it is the number of rounds that'll occur?
i am going to use it to track current round, maybe i should rename it to completed_rounds for clarification
but because player 1 is the dealer round 1, and player 2 is the dealer round 2, i can just use it as an index for which thread runs the dealer function that round
the number of rounds that occur is just a hard coded 6
is the number of people playing always 6?
do they specifically want you to use a vector of vectors for the player's hand?
the number is always 6 and i chose a vector of vectors cuz i thought it would be easier to add and remove from
want able to figure out the condition variables so im going to keep using barriers and hope it works they way i want it to
ima step away to shower off, my current plan of action is as follows, ill see how it works later:
#include <stdio.h>
#include <iostream>
#include <stdlib.h>
#include <string.h>
//#include <sys/resource.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <pthread.h>
#include <queue>
#include <vector>
#include <algorithm>
#include <ctime>
using namespace std;
vector<int> deck;
vector< vector<int> > playerHands;
volatile int target_card;
volatile bool winner = false;
volatile int completed_rounds = 0;
// create a mutex
pthread_mutex_t deck_mutex;
pthread_mutex_t turn_mutex;
pthread_mutex_t round_mutex;
pthread_barrier_t barrier;
// Initialize threads
pthread_t* const handle = new pthread_t[6];
static void* game( void* arg );
static void dealer( long my_rank );
static void player( long my_rank );
int main(){
//fill the deck 1-13, face cards are 11, 12, 13
for( int i = 1; i <= 13; i++){
// push 1 value for each suit
deck.push_back( i );
deck.push_back( i );
deck.push_back( i );
deck.push_back( i );
}
// Shuffle the vector
srand(time(NULL));
random_shuffle(deck.begin(), deck.end());
// Print the shuffled deck (for testing purposes)
for (const auto &card : deck) {
cout << card << " ";
}
//initialize players hands vectors
for( int i = 0; i < 6; i++){
// Pushes a epmty vector for each players hand
// locate each player via vector index playerHands[player # - 1]
playerHands.push_back(vector<int>());
}
pthread_mutex_init( &deck_mutex, NULL );
pthread_mutex_init( &turn_mutex, NULL );
pthread_mutex_init( &round_mutex, NULL );
pthread_barrier_init(&barrier, NULL, 6);
for( int i = 0; i < 6; i++ ){
pthread_create(&handle[i], NULL, game, (void*)i);
}
}
static void* game( void* arg ){
const long my_rank = (long)arg;
for( int i = 0; i < 6; i++){
//pick dealer
if( my_rank == completed_rounds ){
dealer( my_rank );
}
//pick players
if( my_rank != completed_rounds ){
player( my_rank );
}
}
return NULL;
}
static void dealer( long my_rank ){
cout << endl << my_rank << endl;
pthread_mutex_lock( &deck_mutex );
//pick a target card from top of deck
target_card = deck.front();
deck.erase(deck.begin());
//deal a card to each players hand
for( int i = 0; i < 6; i++ ){
if ( i != completed_rounds ){
playerHands[i].push_back(deck.front());
deck.erase(deck.begin());
}
}
pthread_mutex_unlock(&deck_mutex);
// Players do the rest of the functionality
pthread_barrier_wait(&barrier);
}
static void player( long my_rank ){
// Buffer that will stop all threads until all 6 reach barrier
pthread_barrier_wait(&barrier);
bool did_i_win = false;
//players then take turns in RR (ignoring dealer) pulling 1 card from the deck
while( !winner ){
pthread_mutex_lock( &deck_mutex );
//double check if theres not a winner
if( !winner ){
//pull a card from the deck and add to players hand
//check to see if either of the cards in players hand match the target card
//if a card matches then this player wins, winner = true, completed_rounds++, puts both cards back into the deck
//else this player didnt win and puts 1 card back into the deck at random
}
else {
// a player already won
// return the cards to the back of the deck
}
pthread_mutex_lock( &deck_mutex );
}
}
if the number of people playing is always 6, you can use an array of vectors - it's a lot easier
and now i see what you're doing with completed_rounds - it's very finnicky, however
have you been introduced to creating your own classes yet?
i dont really see a purpose for adding classes or structs to this task
i could make a card struct but i only need a int value for my output
trust me lol
ok so this is what i have
#include <stdio.h>
#include <iostream>
#include <stdlib.h>
#include <string.h>
//#include <sys/resource.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <pthread.h>
#include <queue>
#include <vector>
#include <algorithm>
#include <ctime>
using namespace std;
vector<int> deck;
vector<int> playerHands[6];
static int target_card;
volatile bool winner = false;
volatile int completed_rounds = 0;
// create a mutex
pthread_mutex_t deck_mutex;
pthread_mutex_t turn_mutex;
pthread_mutex_t round_mutex;
pthread_barrier_t barrier;
// Initialize threads
pthread_t* const handle = new pthread_t[6];
static void* game( void* arg );
static void dealer( long my_rank );
static void player( long my_rank );
int main(){
//fill the deck 1-13, face cards are 11, 12, 13
for( int i = 1; i <= 13; i++){
// push 1 value for each suit
deck.push_back( i );
deck.push_back( i );
deck.push_back( i );
deck.push_back( i );
}
// Shuffle the vector
srand(time(NULL));
random_shuffle(deck.begin(), deck.end());
// Print the shuffled deck (for testing purposes)
for (const auto &card : deck) {
cout << card << " ";
}
//initialize players hands vectors
for( int i = 0; i < 6; i++){
// Pushes a epmty vector for each players hand
// locate each player via vector index playerHands[player #]
playerHands[i] = vector<int>();
}
pthread_mutex_init( &deck_mutex, NULL );
pthread_mutex_init( &turn_mutex, NULL );
pthread_mutex_init( &round_mutex, NULL );
pthread_barrier_init(&barrier, NULL, 6);
for( int i = 0; i < 6; i++ ){
pthread_create(&handle[i], NULL, game, (void*)i);
}
}
static void* game( void* arg ){
const long my_rank = (long)arg;
for( int i = 0; i < 6; i++){
//pick dealer
if( my_rank == completed_rounds ){
dealer( my_rank );
}
//pick players
if( my_rank != completed_rounds ){
player( my_rank );
}
}
return NULL;
}
static void dealer( long my_rank ){
cout << endl << my_rank << endl;
pthread_mutex_lock( &deck_mutex );
//pick a target card from top of deck
target_card = deck.front();
deck.erase(deck.begin());
cout << "PLAYER " << my_rank + 1 << " is DEALER: target card is " << target_card << endl;
//deal a card to each players hand
for( int i = 0; i < 6; i++ ){
if ( i != completed_rounds ){
playerHands[i].push_back(deck.front());
deck.erase(deck.begin());
}
}
pthread_mutex_unlock(&deck_mutex);
// Players do the rest of the functionality
pthread_barrier_wait(&barrier);
}
static void player( long my_rank ){
// Buffer that will stop all threads until all 6 reach barrier
pthread_barrier_wait(&barrier);
bool did_i_win = false;
//players then take turns in RR (ignoring dealer) pulling 1 card from the deck
while( !winner ){
pthread_mutex_lock( &deck_mutex );
//double check if theres not a winner
if( !winner ){
cout << "PLAYER " << my_rank + 1 << ": hand (" << playerHands[my_rank].front() << ")" << endl;
//pull a card from the deck and add to players hand
int card = deck.front();
deck.erase(deck.begin());
playerHands[my_rank].push_back(card);
cout << "PLAYER " << my_rank + 1 << ": draws " << card << endl;
cout << "PLAYER " << my_rank + 1 << ": hand (" << playerHands[my_rank].front() << "," << playerHands[my_rank].back() << ")"
<< "<> target card is " << target_card << endl;
//check to see if either of the cards in players hand match the target card
for (int i = 0; i < playerHands[my_rank].size(); i++) {
//if a card matches then this player wins, winner = true, completed_rounds++, puts both cards back into the deck
if (playerHands[my_rank][i] == target_card){
did_i_win = true;
completed_rounds++;
//put back target card
deck.push_back( target_card );
//put back both cards from player's hand
card = playerHands[my_rank].front();
playerHands[my_rank].erase(playerHands[my_rank].begin());
deck.push_back( card );
card = playerHands[my_rank].front();
playerHands[my_rank].erase(playerHands[my_rank].begin());
deck.push_back( card );
}
}
//else this player didnt win and puts 1 card back into the deck at random
if (!did_i_win) {
// Player didn't win, put 1 card back into the deck at random
int random_index = rand() % playerHands[my_rank].size();
cout << "PLAYER " << my_rank + 1 << ": discards " << playerHands[my_rank][random_index] << " at random" << endl;
deck.push_back(playerHands[my_rank][random_index]);
playerHands[my_rank].erase(playerHands[my_rank].begin() + random_index);
}
}
else {
// a player already won
// return the cards to the back of the deck
int card = playerHands[my_rank].front();
playerHands[my_rank].erase(playerHands[my_rank].begin());
deck.push_back( card );
}
pthread_mutex_lock( &deck_mutex );
}
if( did_i_win ){
cout << "PLAYER " << my_rank + 1 << ": won round " << completed_rounds << endl;
}
else{
cout << "PLAYER " << my_rank + 1 << ": lost round " << completed_rounds << endl;
}
}
and what i get is:
[qgk11@eros ~]$ ./matching
4 12 1 8 6 10 2 4 7 6 2 11 13 7 5 7 9 5 2 10 8 1 3 3 13 13 6 3 12 13 9 12 4 5 11 9 1 8 12 2 8 1 6 11 3 10 7 9 11 4 5 10
0
PLAYER 1 is DEALER: target card is 4
PLAYER 3: hand (-1709831264)
however i did just notice i did not clean up correctly
and a typo on unlocking mutex
ok my code is now this whole thing
but my output is:
what am i not understanding about vectors that is causing conditions not to work?
made more alterations and getting closer to working results
i may need to rethink my architecture. I dont know how to control the order of the threads, some threads let go of the mutex but then acquire it again immediately, when i thought mutexes were first come first server
😦
!solved