问题
Lets say I initialized two global arrays of semaphores,
semaphore empty[someNum];
and
semaphore full[someNum];
and someNum is initialized as
const int someNum = 3; (globally)
I'll have a method called init() and inside is a for-loop to help index those arrays.
for (index=0; index<someNum; index++) num[index]=0;
my goal is to use commands like wait and signal certain semaphores in the array, for example if num is full, then I do not want my producer to place a value into it.
inside of init() I know that I need to initialize all the semaphores in the loop body. So far I have tried
empty[index] = create_semaphore(1)
full[index] = create_semaphore(0)
and inside of the methods I want to preform the actions wait and signal I tried for example
wait(empty) ;
but I get back errors. I know it is because I am using the name of the array and not a specific semaphore.
So my question is, how do I properly index into my arrays in my for-loop to specify one semaphore?
Thanks for any and all inputs! If you have any questions feel free to ask for any clarification! And please be patient with me, semaphores are a new concept to me.
NOTE
the command create_semaphore exists in another program affiliated with this one.
EDIT
foodPass.cpp
#include <iostream>
#include <sched.h>
#include <time.h>
#include <pthread.h>
#include <string>
#include "sem.h"
using namespace std ;
/* ######################################## */
/* Misc Data Types */
/* ######################################## */
/* A data type - a struct with an int field
to represent a child ID at the program level. */
struct threadIdType
{
int id ;
};
/* ######################################## */
/* Global Variables */
/* ######################################## */
//const int numTrivets = 6 ;
const int numTrivets = 3 ;
const int numDiners = numTrivets - 1 ;
const int maxDishNames = 13 ;
//const int numDishNames = 13 ;
const int numDishNames = 5 ;
int trivet[numTrivets] ;
string dishName[maxDishNames];
/* Here declare the semaphores and other variables you will
need to synchronize threads. */
sim_semaphore empty[numTrivets] ;
sim_semaphore full[numTrivets] ;
/* child_t are global variables to represent the
dynamically-created threads. */
pthread_t child_t[numTrivets] ;
/* ######################################## */
/* "Special" Global Variables */
/* ######################################## */
/* Code in sem.cpp "expects" the two variables below to be here.
This particular program does not use "checking." */
/* "Checking" is just a flag that you set to 1 if you want lots of
debugging messages and set to 0 otherwise. The semaphore code in
sem.cpp imports "checking". Therefore the semaphore operations
will write lots of messages if you set checking=1. */
int checking ;
/* In some programs, we use the "stdoutLock" variable declared below to
get intelligible printouts from multiple concurrent threads that write
to the standard output. (There has to be something to prevent the
output of the threads from interleaving unintelligibly on the standard
output, and we can't use semaphores if the semaphore code is writing
messages too.)
To print a message to standard output, a thread first locks standard
output, then writes, then unlocks standard output. See files sem.cpp
or conc.cpp for examples of code that write messages in this manner.
WARNING: DON'T change how the locking of standard output is done
until you've thought a WHOLE lot about the consequences. In
particular, using semaphores to do the job of stdoutLock can cause
"infinite recursion" under certain circumstances. The reason is that
the semaphore code itself imports "stdoutLock" and writes messages
when the "checking" variable is set to 1. */
pthread_mutex_t stdoutLock ;
/* ################################################## */
/* init */
/* ################################################## */
void init()
{
int index ;
srandom(time((time_t *) 0)); /* INITIALIZE RANDOM NUMBER GENERATOR */
checking = 0 ;
/* Initialize the "special lock" that is used only to get
exclusive access to the screen. */
if ( 0!=pthread_mutex_init(&stdoutLock, NULL) )
{ cout << "MUTEX INITIALIZATION FAILURE!" << endl;
exit(-1) ;}
/* Initialize the trivets to indicate that each contains "no
dish." */
for (index=0; index<numTrivets; index++) trivet[index]=0;
/* Here initialize the semaphores and other variables you use
for synchronization. */
for (index=0; index<numTrivets; index++) full[index] = create_sim_sem(0) ;
for (index=0; index<numTrivets; index++) empty[index] = create_sim_sem(1) ;
/* Give some mnemonic names to the dishes. The first name is
used for an empty trivet. The last name denotes the check
(bill) for the meal. This is coded so no changes are needed
here as long as the value of "numDishNames" is between 2 and
13. */
dishName[0]="no dish";
dishName[1]="vegetable soup" ;
dishName[2]="bread and butter" ;
dishName[3]="beets and chickpeas" ;
dishName[4]="hardboiled eggs" ;
dishName[5]="calf tongue" ;
dishName[6]="baked potato" ;
dishName[7]="string beans" ;
dishName[8]="rack of lamb" ;
dishName[9]="salad" ;
dishName[10]="coffee" ;
dishName[11]="flan" ;
dishName[numDishNames-1]="check" ;
}
/* ################################################## */
/* DelayAsMuchAs */
/* ################################################## */
void delayAsMuchAs (int limit)
{
int time, step;
time=(int)random()%limit;
for (step=0;step<time;step++) sched_yield() ;
}
/* ################################################## */
/* Server */
/* ################################################## */
/*
The mother thread spawns a child thread that executes this
function. This function carries out the job of the server
at the restaurant.
*/
void * Server(void * ignore)
{
int i, j, delayLimit=100 ;
for (i=1; i<numDishNames; i++)
{
/* I delay a random time before I "feel like" placing
another dish on the table.*/
delayAsMuchAs(delayLimit);
/* When the trivet is available, I place the dish on the
trivet to my right. */
/* Here do a synchronization task. One thing you need to
do is be sure that you are not going to place a dish on
a trivet that alreay has a dish on it. *DO NOT* just
busy-wait until you see that the trivet is empty. */
wait_sem(empty[i]) ;
trivet[0]=i; // put dish #i onto trivet #0
pthread_mutex_lock(&stdoutLock) ;
cout << "Server places " << dishName[trivet[0]]
<< " on trivet #0." << endl ;
pthread_mutex_unlock(&stdoutLock);
/* Here you may want to a synchronization task --
something that "opens the door" for diner #0 to get
access to the new dish. */
signal_sem(full[i]) ;
}
pthread_exit ((void *)0) ;
}
/* ################################################## */
/* Diner */
/* ################################################## */
/*
The mother thread spawns child threads that execute this
function. This function carries out the job of one of the
diners at the restaurant.
*/
void * Diner(void * postnPtr)
{
/* Type cast the parameter to recover "position" -- which
tells me the position at which I am seated at the
table. */
int position = ((threadIdType *)(postnPtr))->id ;
int i, j, delayLimit=100 ;
for (i=1; i<numDishNames; i++)
{
/* I delay a random time before I "feel like" picking up the next
dish.*/
delayAsMuchAs(delayLimit);
/* When available, I pick up the next new dish on my left. */
/* Here do a synchronization task. One thing you need to
do is be sure that there is a new dish on the trivet to
your left now, and that the person on your left has
"let go" of it. */
wait_sem(full[i]);
/* I declare what I am doing */
pthread_mutex_lock(&stdoutLock) ;
cout << "Diner number "<< position ;
if (i<numDishNames-1) cout << " enjoys ";
else if (position<numDiners-1) cout << " examines " ;
else cout << " examines and pays " ;
cout << dishName[trivet[position]] << endl ;
pthread_mutex_unlock(&stdoutLock);
/* I delay a random time to simulate the time it takes for me to
serve myself some of what is on the dish -- or look at the
check. */
delayAsMuchAs(delayLimit);
/* When available, I place the dish on the trivet to my right. */
/* Here do a synchronization task. One thing you need to
do is be sure that the trivet on your right does not
have a dish on it now.*/
wait_sem (empty[i]);
pthread_mutex_lock(&stdoutLock) ;
cout << "Diner number "<< position << " moves "
<< dishName[trivet[position]] << " from trivet #"
<< position << " to trivet #" << position+1 << endl;
pthread_mutex_unlock(&stdoutLock);
/* transfer the dish on my left to trivet on my right */
trivet[position+1]=trivet[position] ;
/* mark trivet on my left as empty */
trivet[position]=0;
/* Here do a synchronization task. You have transferred a
dish from your left to your right. The person on your
left will need to find out that the trivet on your left
is now empty. The person on your right will need to
find out that the trivet on your right now has a new
dish on it. */
signal_sem(empty[i]);
signal_sem(full[i]);
}
delete((threadIdType *)(postnPtr)) ;
pthread_exit ((void *) 0) ;
}
/* ################################################## */
/* Busser */
/* ################################################## */
/*
The mother thread spawns children and then executes this
function. This is convenient because this function should
be the last to exit. This function carries out the job of
the busser at the restaurant.
*/
void * Busser (void * ignore)
{
int i, j, delayLimit=100 ;
for (i=1; i<numDishNames; i++)
{
/* I delay a random time before I "feel like" bussing another
dish.*/
delayAsMuchAs(delayLimit);
/* When another dish is on the trivet to my right I remove it. */
/* Here do a synchronization task. One thing you need to
do is be sure that there is a new dish on the trivet to
your left now, and that the person on your left has
"let go" of it. */
wait_sem (full[i]) ;
pthread_mutex_lock(&stdoutLock) ;
cout << "Busser removes "
<< dishName[trivet[numTrivets-1]] << " from trivet #"
<< numTrivets-1<< "." << endl ;
pthread_mutex_unlock(&stdoutLock);
trivet[numTrivets-1]=0; // remove the dish.
/* Here do a synchronization task. The person on your left
will need to find out that the trivet on your left is
now empty. */
signal_sem (empty[i]);
}
return ignore ;
}
/* ################################################## */
/* Main */
/* ################################################## */
int main()
{
init();
cout << endl << endl;
cout << "Welcome to the restaurant!" << endl ;
cout << numDiners << " will be dining." << endl ;
cout << "The meal will consist of " << numDishNames-2
<< " dishes." << endl;
cout << "Bon appetite!" << endl ;
cout << endl << endl;
int i;
/* This is a pointer to a struct that contains an int
field - it is a convenient data type to use as the
parameter to the child function. */
threadIdType * idPtr ;
for (i=0; i<numDiners; i++)
{
/* This records the current index as this child's ID */
idPtr = new threadIdType ;
idPtr->id = i ;
if (0!=pthread_create(&child_t[i], NULL, Diner, (void *) idPtr))
{cout << "THREAD CREATION FAILURE!" << endl; exit(-1) ;}
if (0!=pthread_detach(child_t[i]))
{cout << "THREAD DETACHMENT FAILURE!" << endl ; exit(-1) ;}
}
if (0!=pthread_create(&child_t[numDiners], NULL, Server, (void *) 0))
{cout << "THREAD CREATION FAILURE!" << endl; exit(-1) ;}
if (0!=pthread_detach(child_t[numDiners]))
{cout << "THREAD DETACHMENT FAILURE!" << endl ; exit(-1) ;}
Busser((void *) 0) ;
cout << endl << endl;
cout << "Thank you for coming!" << endl ;
cout << endl << endl;
return 0 ;
}
回答1:
Ok I found out my problem.
Though I correctly initialized my index arrays in init(),
for (index=0; index<numTrivets; index++) full[index] = create_sim_sem(0) ;
for (index=0; index<numTrivets; index++) empty[index] = create_sim_sem(1) ;
My problem actually came from the wait and signal commands.
In server() is a pure producer and is only responsible for the first array index 0 so the commands are simply
wait_sem(empty[0]) and signal_sem(full[0])
In diner() it is a little more complicated. It acts as a hybrid between producer and consumer, meaning we cannot just use 0 and 1, so we look at how trivet[] indexed a single semaphore and borrow that, then we get
wait_sem(full[position])
furthermore, there are two positions the diner() has to worry about. So, we have to make the next position exclusive so we initialize trivet[position+1] and once again borrow that when we are dealing with waits and signals that are to their right.
Lastly, we have busser() who acts purely as a consumer. We only signal him when his spot is full for him to consume. Since the number of trivets are interchangeable, (numTrivets) we cannot simply put in 1 because there can be more than 2 spots next time. Therefore, we need only to put in commands like
wait_sem(full[numTrivets-1]) and then signal_sem(empty[numTrivets-1])
and then I get my desired output.
Thank you to everyone who gave me input I hope my answer proves useful to all those who were confused like myself
来源:https://stackoverflow.com/questions/33471844/indexing-into-an-array-of-semaphores