In this lab you will simulate simple multithreading application with “producer a
ID: 3757119 • Letter: I
Question
In this lab you will simulate simple multithreading application with “producer and consumer” problem.
Modify “Producer and Consumer Problem” from lecture note (See Below) so that it can use all buffer space, not “buffersize – 1” as in the lecture note. This program should work as follows:
- The user will run the program and will enter two numbers on the command line. Those numbers will be used for buffersize and counter limit.
- The main program will then create separate threads, producer and consumer thread.
- Producer thread generates a random number through random number generator function and inserts this into buffer and prints the number. Increment counter.
- Consumer thread goes to the buffer and takes a number in the proper order and prints it out. Increment counter.
- After counter reaches its limit, both threads should be terminated and return to main.
- Main program terminates.
Implement this project in Windows OS. Please use C++ programming language for the program and sample run should clearly show that you implemented subtasks using separate threads.
*****Please explain/comment each line of code, so anyone can know what the code is doing.*****
Lecture Notes of Program below:
Example code
// First, always include <windows.h> for all the Win32 specific thread information
#include <windows.h> #include <iostream.h> #define MAX_THREADS 3
// Prototypes are good and handy, but not necessary in this example. // These three functions are run by each of our three threads
// Please note how the functions are declared:
// In Win32, thread functions MUST be declared like this:
// DWORD WINAPI <name>(LPVOID)
// In short,
// Return value *must* be DWORD WINAPI // And the parameter must be LPVOID
DWORD WINAPI genericThreadFunc1(LPVOID);
DWORD WINAPI printString(LPVOID); DWORD WINAPI printNumber(LPVOID);
// We need an array of Handles to threads
HANDLE hThreads[MAX_THREADS]; // ...an array of thread id's
DWORD id[MAX_THREADS];
// And a waiter (which I'll explain later)
DWORD waiter;
// Here are the three functions that are defined.
// They do trivial things and should be mostly self explanatory.
DWORD WINAPI genericThreadFunc1(LPVOID n)
{
cout << "Thread started (genericThreadFunc1)..." << endl; for(int i = 0; i < 100; i++) {
cout << "threadFunc1 says: " << i << endl; }
cout << "...(genericThreadFunc1) Thread terminating." << endl;
return (DWORD)n; }
DWORD WINAPI printString(LPVOID n)
{
cout << "Thread started (printString)..." << endl;
// NOTE: In the next line, we make a pointer and cast what was passed in.
// This is how you use the LPVOID parameters passed into the
// CreateThread call (below).
char* str = (char*)n;
for(int i = 0; i < 50; i++) {
cout << "printString says: " << str << endl;
}
cout << "...(printString) Thread terminating." << endl;
return (DWORD)n;
}
DWORD WINAPI printNumber(LPVOID n)
{
cout << "Thread started (printNumber)..." << endl;
int num = (int)n;
for (int i = num; i < (num + 100); i++) {
cout << "printNumber says: " << i << endl;
}
cout << "...(printHello) Thread terminating." << endl;
return (DWORD)n;
}
// Get ready, because here's where all the *REAL* magic happens
int main(int argc, char* argv[ ])
{
int CONSTANT = 2000;
char myString[20];
strcpy(myString,"Threads are Easy!");
// Here is where we call the CreateThread Win32 API Function that actually
// creates and begins execution of a thread.
// Please read your help files for what each parameter does on
// your Operating system.
// Here's some basics:
// Parameter 0: Lookup
// Parameter 1: Stack size (0 is default which means 1MB)
// Parameter 2: The function to run with this thread
// Parameter 3: Any parameter that you want to pass to the thread function
// Parameter 4: Lookup
// Parameter 5: Once thread is created, an id is put in this variable passed in
hThreads[0] = CreateThread(NULL,0,genericThreadFunc1,(LPVOID)0,NULL,&id[0]);
hThreads[1] = CreateThread(NULL,0,printString,(LPVOID)myString,NULL,&id[1]);
hThreads[2] = CreateThread(NULL,0,printNumber,(LPVOID)CONSTANT,NULL,&id[2]);
// Now that all three threads are created and running, we need to stop the primary thread
// (which is this program itself - Remember that once "main" returns, our program exits)
// So that our threads have time to finish. To do this, we do what is called "Blocking".
// We're going to make main just stop and wait until all three threads are done.
// This is done easily with the next line of code. Please read the help file about
// the specific API call "WaitForMultipleObjects".
waiter = WaitForMultipleObjects(MAX_THREADS, hThreads, TRUE, INFINITE);
// After all three threads have finished their task, "main" resumes and we're now ready
// to close the handles of the threads. This is just a bit of clean up work.
// Use the CloseHandle (API) function to do this. (Look it up in the help files as well)
for(int i = 0; i < MAX_THREADS; i++) {
CloseHandle(hThreads[i]);
}
return 0;
}
Example code using Win32 API in the Textbook
// First, always include <windows.h> for all the Win32 specific thread information
#include <windows.h>
#include <stdio.h>
DWORD Sum; /* data is shared by the thread(s) */
/* the thread runs in this separate function */
DWORD WINAPI Summation(LPVOID Param)
{
DWORD Upper = *(DWORD*)Param;
for (DWORD i=0; i <= Upper; i++)
Sum += i;
return 0;
}
int main(int argc, char* argv[ ])
{
DWORD ThreadId;
HANDLE ThreadHandle;
int Param;
/* perform some basic error checking */
if (argc != 2) {
fprintf(stderr, “An integer parameter is required ”);
return -1;
}
Param = atoi(argv[1]);
if (Param < 0) {
fprintf(stderr, “An integer >= 0 is required ”);
return -1;
}
/* create the thread */
ThreadHandle = CreateThread(
NULL, // default security attributes
0, // default stack size
Summation, // thread function
&Param, // parameter to thread function
0, // default creation flags
&ThreadId); // returns the thread identifier
if (ThreadHandle != NULL) {
// now wait for the thread to finish
WaitForSingleObject(ThreadHandle, INFINITE);
// close the thread handle
CloseHandle(ThreadHandle);
printf(“sum = %d ”, Sum);
}
}
Explanation / Answer
#include <iostream>
#include <thread>
#include <mutex>
#include <condition_variable>
std::mutex mtx;
std::condition_variable cv;
int meal = 0;
/* Consumer */
void waiter(int ordernumber){
std::unique_lock<std::mutex> lck(mtx);
while(meal == 0) cv.wait(lck);
std::cout << "Order: ";
std::cout << ordernumber + 1 << " being taken care of with ";
std::cout << meal - 1 << " meals also ready." << std::endl;
meal--;
}
/* Producer */
void makeMeal(int ordernumber){
std::unique_lock<std::mutex> lck(mtx);
meal++;
cv.notify_one();
}
int main(){
std::thread chefs[10];
std::thread waiters[10];
/* Initialize customers and cheifs */
for (int order = 0; order < 10; order++){
chefs[order] = std::thread(makeMeal, order);
waiters[order] = std::thread(waiter, order);
}
/* Join the threads to the main threads */
for (int order = 0; order < 10; order++) {
waiters[order].join();
chefs[order].join();
}
return 0;
}
Output:
Order: 3 being taken care of with 0 meals also ready.
Order: 5 being taken care of with 0 meals also ready.
Order: 2 being taken care of with 1 meals also ready.
Order: 6 being taken care of with 0 meals also ready.
Order: 7 being taken care of with 2 meals also ready.
Order: 8 being taken care of with 2 meals also ready.
Order: 9 being taken care of with 2 meals also ready.
Order: 4 being taken care of with 2 meals also ready.
Order: 10 being taken care of with 1 meals also ready.
Order: 1 being taken care of with 0 meals also ready.
Related Questions
drjack9650@gmail.com
Navigate
Integrity-first tutoring: explanations and feedback only — we do not complete graded work. Learn more.