hungryBees.cpp (100 Points)There is a farmer who wants honey.
- Overview:
- There are 4 bee hives that are willing to give honey, but want flowers in return.
- Thefarmerthread runs a loop that only stops when:honey >= NUM_BEE_HIVES. Until then, the farmer patiently makes another flower withnew Flowerand gives it to one of the bee hives.
- Thebee hivethreads collectFlowerinstances and add them to their own personalGardeninstances. When theirGardeninstances haveNUM_FLOWERS_TO_COLLECTflowers, then they increment thehoneycounter for the farmer.
- Cut-and-paste the following:
/*-------------------------------------------------------------------------*
*--- ---*
*--- hungryBees.cpp ---*
*--- ---*
*--- This file defines a C-ish C++ program that exercises ---*
*--- knowledge of POSIX threads and linked list manipulation. ---*
*--- ---*
*--- ---- ---- ---- ---- ---- ---- ---- ---- ---*
*--- ---*
*--- Version 1a ---*
*--- ---*
*-------------------------------------------------------------------------*/
//--- Header file inclusion: ---//
#include
#include
#include
#include
#include
#include
//--- Definition of constants: ---//
// PURPOSE: To tell how many flowers each bee hive must visit.
const int NUM_FLOWERS_TO_COLLECT
= 5;
// PURPOSE: To tell the number of bee hives that exist.
const int NUM_BEE_HIVES = 4;
// PURPOSE: To hold the names of the flowers:
const char* FLOWER_NAME_ARRAY[]
= { "Jasmine",
"Daffodil",
"Stinging Nettle",
"Dandelion",
"Venus fly trap",
"Tumbleweed",
"Kudzu",
"Poison Ivy"
};
// PURPOSE: To tell how many flower names there are.
const size_t NUM_FLOWER_NAMES= sizeof(FLOWER_NAME_ARRAY)/sizeof(const char*);
//--- Definition of classes and structs: ---//
// PURPOSE: To represent a flower.
class Flower
{
// I. Member vars:
// PURPOSE: To hold address of the name of the flower as a C-string.
const char* nameCPtr_;
// PURPOSE: To hold the address of the Flower instance after '*this' one,
// or 'NULL' if there is no such Flower.
Flower* nextPtr_;
// II. Disallowed auto-generated methods:
// No copy constructor:
Flower (const Flower&);
// No copy assignment op:
Flower& operator= (const Flower&);
protected :
// III. Protected methods:
public :
// IV. Constructor(s), assignment op(s), factory(s) and destructor:
// PURPOSE: To make '*this' a stand-alone Flower instance with a randomly-
// chosen name. No parameters. No return value.
Flower () :
nameCPtr_(FLOWER_NAME_ARRAY[rand() %
NUM_FLOWER_NAMES]
),
nextPtr_(NULL)
{ }
// PURPOSE: To release the resources of '*this'. No parameters. No
// return value.
~Flower ()
{ }
// V. Accessors:
// PURPOSE: To return the name of the flower. No parameters.
const char* getNameCPtr ()
const
{ return(nameCPtr_); }
// PURPOSE: To return the address of the Flower instance after '*this' one,
// or 'NULL' if there is no such Flower.
Flower* getNextPtr ()
const
{ return(nextPtr_); }
// VI. Mutators:
// PURPOSE: To note that the next flower in the list has address
// 'newNextPtr'. No return value.
void setNextPtr (Flower* newNextPtr
)
{ nextPtr_ = newNextPtr; }
// VII. Methods that do main and misc work of class:
};
class Garden
{
// I. Member vars:
// YOUR MEMBER VARS HERE
// II. Disallowed auto-created methods:
// No copy constructor:
Garden (const Garden&);
// No copy assignment op:
Garden& operator= (const Garden&);
protected :
// III. Protected methods:
public :
// IV. Constructor(s), assignment op(s), factory(s) and destructor:
// PURPOSE: To initialize '*this' to an empty garden. No parameters.
// No return value.
Garden ()
{
// INITIALIZE HERE
}
// PURPOSE: To release the resources of '*this'. No parameters.
// No return value.
~Garden ()
{
// GET RID OF LIST HERE
}
// V. Accessor(s):
// PURPOSE: To hold length of '*this' list.
int getNumFlowers ()
const
{ return(0); /* CHANGE THAT 0 */}
// VI. Mutator(s):
// VII. Methods that do main and misc. work of class:
// PURPOSE: To add the Flower with address 'flowerPtr' at the back of
// '*this' Garden of Flower instances. No return value.
void store (Flower* flowerPtr
)
{
// ADD TO LIST HERE
}
// PURPOSE: To print this list of Flower instances in '*this' Garden.
// No parameters. No return value.
void print ()
{
// ADD TO LIST HERE
}
};
struct Hive
{
std::string name_;
Garden* gardenPtr_;
Hive () :
name_(""),
gardenPtr_(NULL)
{ }
~Hive ()
{
delete(gardenPtr_);
}
const char* getNameCPtr ()
const
{ return(name_.c_str()); }
};
//--- Definition of global vars: ---//
// PURPOSE: To hold the address of the flower offered by the farmer.
// or to hold 'NULL' if there is no such Flower.
Flower* availableFlowerPtr = NULL;
// PURPOSE: To tell how much honey has been produced by the bee hives.
int honey = 0;
// YOUR CODE HERE to add global vars to control access to availableFlowerPtr and honey:
//--- Definition of main functions: ---//
// PURPOSE: To be the function run by the bee hive threads. 'vPtr' points
// to an instance of 'Hive'. Returns 'NULL'.
void* hive (void* vPtr
)
{
// I. Application validity check:
// II. Get the flowers:
// II.A. Initialize local vars:
Hive* hivePtr = NULL; // CHANGE THAT NULL
Garden* gardenPtr = NULL; // CHANGE THAT NULL
// II.B. Each iteration obtains another Flower instance for the graden
// of Hive '*hivePtr':
while (gardenPtr->getNumFlowers() < NUM_FLOWERS_TO_COLLECT)
{
// YOUR CODE HERE: Make access to availbleFlowerPtr thread-safe
while (availableFlowerPtr == NULL)
{
printf("%s: "Hey! No flowers, no honey!"n",hivePtr->getNameCPtr());
}
printf("%s: "A %s! Sure we will take that!"n",
hivePtr->getNameCPtr(),availableFlowerPtr->getNameCPtr()
);
gardenPtr->store(availableFlowerPtr);
availableFlowerPtr = NULL;
// Leave this outside critical section:
sleep(rand() % 3); // Please leave this OUT of the critical section
}
// II.C. Add to the honey when have enough flowers:
printf("%s "Finally, enough flowers to make some honey."n",
hivePtr->getNameCPtr()
);
// YOUR CODE HERE: Make incrementing honey thread-save
honey++;
// III. Finished:
return(NULL);
}
// PURPOSE: To be the function run by the farmer thread. 'vPtr' is ignored.
// Returns 'NULL'.
void* farmer (void* vPtr)
{
// I. Application validity check:
// II. Give flowers:
// II.A. Each iteration creates and gives another Flower instance
// until there is sufficient honey:
while (true)
{
// YOUR CODE HERE: Make access to honey thread-safe
if (honey >= NUM_BEE_HIVES)
{
break;
}
printf("Farmer: "I have to gather *more* flowers?!?"n");
// YOUR CODE HERE: Make access to availableFlowerPtr thread-safe
while (availableFlowerPtr != NULL)
{
printf("Farmer: "Hey, you said you wanted"
" a flower, come and take it."n"
);
}
availableFlowerPtr = new Flower;
printf("Farmer: "Okay here is another flower: a %s"n",
availableFlowerPtr->getNameCPtr()
);
// Leave this outside critical section:
sleep(rand() % 3); // Please leave this OUT of the critical section
}
// III. Finished:
printf("Farmer "I *finally* got my honey!"n");
return(NULL);
}
// PURPOSE: To run the program. Ignores command line arguments. Returns
// 'EXIT_SUCCESS' to OS.
int main ()
{
// I. Application validity check:
// II. Have the farmer give Flower instances until sufficient honey
// has been obtained:
// II.A. Randomize random number generator:
srand(getpid());
// II.B. Initialize global vars:
Hive hiveArray[NUM_BEE_HIVES];
// Add something here?
// II.C. Make threads:
// II.C.1. Make bee hive threads:
for (int i = 0; i < NUM_BEE_HIVES; i++)
{
hiveArray[i].name_ = std::string("Hive ") + (char)('A'+i);
hiveArray[i].gardenPtr_ = new Garden;
// Add something here?
}
// II.C.2. Make farmer thread:
// Add something here?
// II.D. Wait for child threads:
// II.D.1. Wait for bee hive threads:
for (int i = 0; i < NUM_BEE_HIVES; i++)
{
// Add something here?
printf("%s has:n",hiveArray[i].getNameCPtr());
hiveArray[i].gardenPtr_->print();
}
// II.D.2. Wait for farmer thread:
// Add something here?
// II.E. Get rid of global vars:
// Add something here?
// III. Finished:
return(EXIT_SUCCESS);
}
- FinishGarden:
- Gardenmust implement a linked list ofFlowerinstances using theFlowermethodsgetNextPtr()andsetNextPtr(). (No cheating and using C++ containers likestd::list,std::vector, etc.)
- Giveclass Garden3 member variables:
- AFlower*to point to the beginning of the list.
- AFlower*to point to the end of the list.
- Anintthat keeps track of the length of the list.
- Initialize your variables in the constructor.
- Get rid of your list in thedestructormethod:~Garden(). In C one gets memory withmalloc()and gives it back withfree(). However, in C++ one gets memory and builds an instance of an object withnew, and one dismantles the instance withdelete().
- Please have a local variable likeflowerPtrand saydelete(flowerPtr)for eachFlowerin the list.
- MakegetNumFlowers()return the how manyFlowerinstances are in the list.
- Makestore()add newFlowerinstanceflowerPtrto the end of the list.
- Makeprint()print theFlowerinstances in the list.
- Make it multi-threaded:
- Inmain()you will need a singlepthread_tfor the farmer thread, and an array ofNUM_BEE_HIVESpthread_tinstances for the bee hive threads.
- Declare your variables in sectionII.B.
- Start your threads in sectionII.C. The bee hive threads should runhive()with the address ofhiveArray[i]passed to them. The farmer thread should runfarmer(). Just passNULLas the argument tofarmer().
- In sectionII.Dwait for all child threads to finish.
- Inhive(), argumentvPtrcomes in pointing to aHive. SethivePtrequal tovPtr(you will need to cast it), and setgardenPtrequal to the address of theGardenowned by the Hive. (Seestruct Hive.)
- Now run it!
- Make it thread-safe:
- Congratulations! If you got this far you have made itmulti-threaded, but notthread-safe.
- To make it thread-safe you will have to add somemutex(es)andcondition(s).
- You need to protect access to two variables:
- availableFlowerPtr, underDefinition of global vars:. This one acts like a one-element buffer.
- The farmer thread has to wait while it has a non-NULLvalue ("is-full").
- The bee hive threads have to wait while it has aNULLvalue ("is-empty").
- honey, also underDefinition of global vars:. UnlikeavailableFlowerPtr, there is no need to wait to use this variable.
- Stop! Think!What needs mutexes? What needs conditions?
- Declare your variables globally in theDefinition of global vars:section
- Initialize those variables inmain()in sectionII.B.
- Destroy those variables inmain()in sectionII.E.
- Use them infarmerto protect access to bothhoneyandavailableFlowerPtr.
- Use them inhiveto protect access to bothavailableFlowerPtrandhoney.
- Questions:
- How well did your program work before making it thread safe?
- How well did your program work after making it thread safe?
- Sample output:
$ ./hungryBees
Farmer: "I have to gather *more* flowers?!?"
Farmer: "Okay here is another flower: a Dandelion"
Farmer: "I have to gather *more* flowers?!?"
Farmer: "Hey, you said you wanted a flower, come and take it."
Hive A: "A Dandelion! Sure we will take that!"
Hive C: "Hey! No flowers, no honey!"
Hive B: "Hey! No flowers, no honey!"
Hive D: "Hey! No flowers, no honey!"
Farmer: "Okay here is another flower: a Stinging Nettle"
Farmer: "I have to gather *more* flowers?!?"
Farmer: "Hey, you said you wanted a flower, come and take it."
Hive C: "A Stinging Nettle! Sure we will take that!"
Farmer: "Okay here is another flower: a Dandelion"
Hive B: "A Dandelion! Sure we will take that!"
Hive B: "Hey! No flowers, no honey!"
Hive A: "Hey! No flowers, no honey!"
Hive C: "Hey! No flowers, no honey!"
Farmer: "I have to gather *more* flowers?!?"
Farmer: "Okay here is another flower: a Jasmine"
Hive D: "A Jasmine! Sure we will take that!"
Hive D: "Hey! No flowers, no honey!"
Farmer: "I have to gather *more* flowers?!?"
Farmer: "Okay here is another flower: a Poison Ivy"
Farmer: "I have to gather *more* flowers?!?"
Farmer: "Hey, you said you wanted a flower, come and take it."
Hive B: "A Poison Ivy! Sure we will take that!"
Farmer: "Okay here is another flower: a Daffodil"
Hive A: "A Daffodil! Sure we will take that!"
Hive A: "Hey! No flowers, no honey!"
Farmer: "I have to gather *more* flowers?!?"
Hive B: "Hey! No flowers, no honey!"
Farmer: "Okay here is another flower: a Daffodil"
Hive C: "A Daffodil! Sure we will take that!"
Farmer: "I have to gather *more* flowers?!?"
Farmer: "Okay here is another flower: a Poison Ivy"
Hive D: "A Poison Ivy! Sure we will take that!"
Hive D: "Hey! No flowers, no honey!"
Hive C: "Hey! No flowers, no honey!"
Farmer: "I have to gather *more* flowers?!?"
Farmer: "Okay here is another flower: a Stinging Nettle"
Farmer: "I have to gather *more* flowers?!?"
Farmer: "Hey, you said you wanted a flower, come and take it."
Hive A: "A Stinging Nettle! Sure we will take that!"
Farmer: "Okay here is another flower: a Stinging Nettle"
Hive B: "A Stinging Nettle! Sure we will take that!"
Hive A: "Hey! No flowers, no honey!"
Farmer: "I have to gather *more* flowers?!?"
Hive B: "Hey! No flowers, no honey!"
Farmer: "Okay here is another flower: a Daffodil"
Farmer: "I have to gather *more* flowers?!?"
Farmer: "Hey, you said you wanted a flower, come and take it."
Hive D: "A Daffodil! Sure we will take that!"
Farmer: "Okay here is another flower: a Tumbleweed"
Hive C: "A Tumbleweed! Sure we will take that!"
Hive D: "Hey! No flowers, no honey!"
Farmer: "I have to gather *more* flowers?!?"
Farmer: "Okay here is another flower: a Tumbleweed"
Hive A: "A Tumbleweed! Sure we will take that!"
Hive C: "Hey! No flowers, no honey!"
Farmer: "I have to gather *more* flowers?!?"
Farmer: "Okay here is another flower: a Poison Ivy"
Hive A: "A Poison Ivy! Sure we will take that!"
Hive A "Finally, enough flowers to make some honey."
Hive B: "Hey! No flowers, no honey!"
Hive A has:
Dandelion
Daffodil
Stinging Nettle
Tumbleweed
Poison Ivy
Farmer: "I have to gather *more* flowers?!?"
Farmer: "Okay here is another flower: a Poison Ivy"
Hive D: "A Poison Ivy! Sure we will take that!"
Farmer: "I have to gather *more* flowers?!?"
Farmer: "Okay here is another flower: a Dandelion"
Hive C: "A Dandelion! Sure we will take that!"
Hive D: "Hey! No flowers, no honey!"
Farmer: "I have to gather *more* flowers?!?"
Farmer: "Okay here is another flower: a Daffodil"
Hive C: "A Daffodil! Sure we will take that!"
Hive C "Finally, enough flowers to make some honey."
Hive B: "Hey! No flowers, no honey!"
Farmer: "I have to gather *more* flowers?!?"
Farmer: "Okay here is another flower: a Venus fly trap"
Hive D: "A Venus fly trap! Sure we will take that!"
Hive D "Finally, enough flowers to make some honey."
Farmer: "I have to gather *more* flowers?!?"
Farmer: "Okay here is another flower: a Poison Ivy"
Farmer: "I have to gather *more* flowers?!?"
Farmer: "Hey, you said you wanted a flower, come and take it."
Hive B: "A Poison Ivy! Sure we will take that!"
Hive B: "Hey! No flowers, no honey!"
Farmer: "Okay here is another flower: a Daffodil"
Hive B: "A Daffodil! Sure we will take that!"
Hive B "Finally, enough flowers to make some honey."
Hive B has:
Dandelion
Poison Ivy
Stinging Nettle
Poison Ivy
Daffodil
Hive C has:
Stinging Nettle
Daffodil
Tumbleweed
Dandelion
Daffodil
Hive D has:
Jasmine
Poison Ivy
Daffodil
Poison Ivy
Venus fly trap
Farmer "I *finally* got my honey!"