So, guys, now, next, let us discuss what are the common APIs that we will going to write in order
to solve our problem.
So now I will going to discuss what are the functions you will going to write in the file assignment
dining philosophers, right.
So to begin with, you can see on the screen the three APIs.
Now, these three APIs are very common APIs and they have nothing to do with the thread synchronization.
In each of these APIs.
You don't have to use any mutex or condition variables and you just have to provide the plain implementation
of these APIs.
So you can see as the first API says, that philosopher get right spoon, it simply means that this
API returns a pointer to the right spoon of the philosopher, which is passed as an argument.
So it simply means, for example, suppose this API is being invoked on the philosopher one.
So this API must return a pointer to the spoon as p zero.
Right?
Similarly, if this API is being invoked on a philosopher zero then it must return a pointer to the
spoon as before.
Right.
Similarly, you have the second API which returns a pointer to the left spoon of the philosopher, which
is passed as an argument.
Right.
So the implementation of these APIs is very simple and easy and we will discuss their implementation
quickly when we will be discussing the complete solution.
The third API is the philosopher eat, which should represent that the philosopher has gotten access
to both of his spoon and this API must block or sleep for one second because as per our constraint,
the philosopher once get an access to both of his spoons.
He enjoyed the cake for one second.
Right.
So enjoying the cake for one second is equal to making this function sleep for one second.
Right.
And the code logic to implement the solution of dining philosopher problem would go in these two APIs.
That is philosopher released both the spoons and philosopher get access both the spoons.
Right?
So the core solution will go in these two APIs.
We will going to discuss the implementation of these two APIs in a step by step manner.
But first, let us set up our assignment dining philosopher dot C file.
So let us set up our skeleton structure of our solution file.
So guys on the screen, you can see that I've opened the file assignment dining philosophers.
And this is the file which represents our assignment file.
It is this file in which you need to provide the solution to dining philosophers problem.
So as you can see, as per our diagram, we have five philosopher, for example.
So five philosopher means you have five spoons.
So it simply means that you can always take some constant value and let us initialize it to five, right?
And now we have to take five philosophers and five spoons.
So you can just take static arrays, which represents the collection of philosopher objects and spoon
objects.
Right?
And now to begin with, the main function.
In the main function, we will going to initialize the philosopher objects and spoon objects, right?
So what we will going to do is that we will going to create a loop.
And in this loop, first of all, we will going to initialize all the spoons.
So you can see that I'm assigning spoon IDs.
And initially to begin with, all the spoons are available.
Therefore is used.
Flag is set to false.
There is no philosopher who is using the spoon.
I therefore it is set to null and initialize the condition variable and the mutex object of the spoons.
Right.
So you can see that every spoon is given a ID starting from zero to n minus one.
As simple as that.
So in this block of code, we have done the initialization of spawn objects.
Now, next we will do the initialization of philosopher objects.
Now, remember, philosophers are nothing, but they are threads.
It is for this reason that I will going to create all the philosopher threads in the detached mode.
Right?
Because eventually they will going to run in an infinite loop.
So.
So those philosopher threads have no use case to join any other thread and hence it is better to create
philosopher threads as detached threads.
So again, I will create a loop and I'm initializing each philosopher object.
Every philosopher is given an id I right, and each count of every philosopher will going to be zero.
And remember that philosophers are nothing but they are threads.
So it is for this reason that the thread which represents a philosopher is being triggered in this line
that is in line number 64.
Right?
And this completes the initialization of spoons and philosophers, right?
Now here you can see that I have passed a philosopher function.
So it is in this philosopher functions.
So it is this philosopher function where we will going to start the implementation of code logic of
our solution.
Right?
The starting point of our solution is this function that is philosopher function.
And remember, this philosopher function will be executed by each philosopher, right?
If you have five philosophers, all five philosophers will going to execute philosopher function concurrently.
Right?
And remember, while writing a solution, you have to write a generic solution.
Meaning that.
You cannot write any piece of code which is specific to some philosopher.
Say philosopher number three.
Right?
It is just not allowed because this philosopher function will be executed by all the philosophers and
you would never know how many philosophers your program can have.
Right?
So the solution that we were going to implement would be generic, and it should work for any number
of philosophers or any number of spoons.
Needless to say, the number of philosophers has to be equal to the number of spoons.
And now, guys.
Next, we will going to implement these supporting APIs.
That is the first three APIs, right?
So to start with, let us implement the function philosopher get right spoon right.
And the implementation of this function is fairly very simple and easy.
This function usually returns the spoon number I minus one for the philosopher I right.
And of course, you need to test out the boundary condition that if the philosopher ID is zero, then
you need to return the spoon number as before as per our diagram.
Right.
Similarly, going forward, you can also provide the implementation of the function philosopher get
slapped spoon and the implementation of this API is even simpler.
Right.
For philosopher K, the left spoon will be K right.
So just return the pointer to the left spoon of the philosopher which is passed as an argument.
And the next API that we will going to implement is the philosopher eat API.
Right.
The invocation of this API represents that this particular philosopher has gotten access to both of
his spoons and this philosopher would going to enjoy the delicious cake for one second.
So you can see that in this API.
First of all, what we will going to do is to simply check that this philosopher, which is passed as
an argument, must have gotten access to both of his spoon, Right.
So you can see that I am getting a pointer to the left spoon and the pointer to the right spoon of this
philosopher using the APIs which we have written above, right?
And once we get a pointer to both of his spoon, now we will assume that both of these spoon have been
already assigned to this philosopher.
Right?
That is why we have invoked the function philosopher Eat.
So it simply means that we will going to check the state of the data structure to verify that left and
right spoon have really been assigned to the philosopher.
So for that you can simply check that the owner of the spoon is the philosopher himself, which is passed
as an argument, right?
And if it is not the case, then you just have to crash your application because you have invoked the
function.
Assuming that the philosopher has been assigned both of his spoons.
But here the state of the data structure is indicating something else, right?
So crashing the program intentionally helps to identify the problems at an early stage and fix them.
And going forward, the is used flag of the left and the right spoon must be set to true right because
the philosopher has already gotten access to both of these spoons.
And finally, when all the conditions which state that the philosopher has rightfully gotten access
to both of his left and right spoons, then in that case we can increment the eat count variable of
the philosopher, meaning that philosopher is now enjoying the delicious cake.
And remember that we had a constraint that philosopher must eat a cake for exactly one second.
Right?
So let the philosopher enjoy his turn of eating for one second.
And this is how we are satisfying our one of the constraint of our problem statement.
Right?
So you can see that these three functions are very simple and plain functions and has nothing to do
with the thread synchronization.
Now that we have these utility functions ready, now we can actually start implementing the main or
core logic of our dining philosopher problem solution, Right?
So in this program we need to provide the implementation of the function philosopher release both spoons,
right?
And we need to provide the implementation to the function philosopher.
Get access, both spoons, right?
So the main solution of this problem statement would be implemented in these two functions.
Plus we need to implement the starting logic in the philosopher function.
Remember, philosopher function is a function which would execute in the context of the philosopher
threads, right?
So the starting point of our solution is the philosopher function, which in turn will make use of these
two functions in order to implement the solution.
So this is the file which is now ready for you and you should start provide the implementation of philosopher
function philosopher get access both spoons and philosopher release both spoons.
Other than that, you don't have to make any other code changes in this file.