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 intNUM_FLOWERS_TO_COLLECT
= 5;
// PURPOSE: To tell the number of bee hives that exist.
const intNUM_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_tNUM_FLOWER_NAMES= sizeof(FLOWER_NAME_ARRAY)/sizeof(const char*);
//--- Definition of classes and structs:---//
// PURPOSE: To represent a flower.
classFlower
{
// 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.
voidsetNextPtr(Flower*newNextPtr
)
{ nextPtr_ = newNextPtr; }
// VII. Methods that do main and misc work of class:
};
classGarden
{
// 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.
intgetNumFlowers()
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.
voidstore(Flower*flowerPtr
)
{
// ADD TO LIST HERE
}
// PURPOSE: To print this list of Flower instances in '*this' Garden.
//No parameters. No return value.
voidprint()
{
// ADD TO LIST HERE
}
};
structHive
{
std::stringname_;
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.
inthoney= 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() <>
{
// 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.
intmain()
{
// 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:
HivehiveArray[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;="">
{
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;="">
{
// 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!"