Program In C For Dining Philosopher Problem

Posted on -

I'm confused and new to this Dining Philosophers Problem. C Programming; Dining Philosophers Problem using Tannenbaum's solution. Dining Philosopher question.

  • Is this implementation correct? Do you find any threading problem? Also, what parts of the code can be changed to be more C++11-ish? #include #include.
  • I am working on the dining philosophers program. However I am running into a problem that my program stops before all of the philosophers have eaten, and I don't.

Illustration of the dining philosophers problem. Five silent sit at a round table with bowls of. Forks are placed between each pair of adjacent philosophers. Each philosopher must alternately think and eat. However, a philosopher can only eat spaghetti when they have both left and right forks. Each fork can be held by only one philosopher and so a philosopher can use the fork only if it is not being used by another philosopher.

After an individual philosopher finishes eating, they need to put down both forks so that the forks become available to others. A philosopher can take the fork on their right or the one on their left as they become available, but cannot start eating before getting both forks. Eating is not limited by the remaining amounts of spaghetti or stomach space; an infinite supply and an infinite demand are assumed. The problem is how to design a discipline of behavior (a ) such that no philosopher will starve; i.e., each can forever continue to alternate between eating and thinking, assuming that no philosopher can know when others may want to eat or think.

Problems The problem was designed to illustrate the challenges of avoiding, a system state in which no progress is possible. To see that a proper solution to this problem is not obvious, consider a proposal in which each philosopher is instructed to behave as follows:. think until the left fork is available; when it is, pick it up;. think until the right fork is available; when it is, pick it up;. when both forks are held, eat for a fixed amount of time;. then, put the right fork down;. Quero voltar ao primeiro amor. then, put the left fork down;.

Program in c for palindrome

repeat from the beginning. This attempted solution fails because it allows the system to reach a deadlock state, in which no progress is possible. This is a state in which each philosopher has picked up the fork to the left, and is waiting for the fork to the right to become available, or vice versa. With the given instructions, this state can be reached, and when it is reached, the philosophers will eternally wait for each other to release a fork. Might also occur independently of deadlock if a particular philosopher is unable to acquire both forks because of a timing problem.

For example, there might be a rule that the philosophers put down a fork after waiting ten minutes for the other fork to become available and wait a further ten minutes before making their next attempt. This scheme eliminates the possibility of deadlock (the system can always advance to a different state) but still suffers from the problem of. If all five philosophers appear in the dining room at exactly the same time and each picks up the left fork at the same time the philosophers will wait ten minutes until they all put their forks down and then wait a further ten minutes before they all pick them up again.

The dining philosophers problem

Is the basic idea of the problem; the dining philosophers create a generic and abstract scenario useful for explaining issues of this type. The failures these philosophers may experience are analogous to the difficulties that arise in real computer programming when multiple programs need exclusive access to shared resources. These issues are studied in. The original problems of Dijkstra were related to external devices like tape drives. However, the difficulties exemplified by the dining philosophers problem arise far more often when multiple processes access sets of data that are being updated. Complex systems such as use thousands of and that require strict adherence to methods and protocols if such problems as deadlock, starvation, and data corruption are to be avoided. Solutions Resource hierarchy solution This solution to the problem is the one originally proposed.

It assigns a to the resources (the forks, in this case), and establishes the convention that all resources will be requested in order, and that no two resources unrelated by order will ever be used by a single unit of work at the same time. Here, the resources (forks) will be numbered 1 through 5 and each unit of work (philosopher) will always pick up the lower-numbered fork first, and then the higher-numbered fork, from among the two forks they plan to use. The order in which each philosopher puts down the forks does not matter.

In this case, if four of the five philosophers simultaneously pick up their lower-numbered fork, only the highest-numbered fork will remain on the table, so the fifth philosopher will not be able to pick up any fork. Moreover, only one philosopher will have access to that highest-numbered fork, so they will be able to eat using two forks. While the resource hierarchy solution avoids deadlocks, it is not always practical, especially when the list of required resources is not completely known in advance. For example, if a unit of work holds resources 3 and 5 and then determines it needs resource 2, it must release 5, then 3 before acquiring 2, and then it must re-acquire 3 and 5 in that order. Computer programs that access large numbers of database records would not run efficiently if they were required to release all higher-numbered records before accessing a new record, making the method impractical for that purpose. Arbitrator solution Another approach is to guarantee that a philosopher can only pick up both forks or none by introducing an arbitrator, e.g., a waiter.

In order to pick up the forks, a philosopher must ask permission of the waiter. The waiter gives permission to only one philosopher at a time until the philosopher has picked up both of their forks. Putting down a fork is always allowed. The waiter can be implemented as a. In addition to introducing a new central entity (the waiter), this approach can result in reduced parallelism: if a philosopher is eating and one of their neighbors is requesting the forks, all other philosophers must wait until this request has been fulfilled even if forks for them are still available. Chandy/Misra solution In 1984, and J.

Misra proposed a different solution to the dining philosophers problem to allow for arbitrary agents (numbered P 1., P n) to contend for an arbitrary number of resources, unlike Dijkstra's solution. It is also completely distributed and requires no central authority after initialization. However, it violates the requirement that 'the philosophers do not speak to each other' (due to the request messages). For every pair of philosophers contending for a resource, create a fork and give it to the philosopher with the lower ID ( n for agent P n). Each fork can either be dirty or clean.

Initially, all forks are dirty. When a philosopher wants to use a set of resources ( i.e. Eat), said philosopher must obtain the forks from their contending neighbors. For all such forks the philosopher does not have, they send a request message. When a philosopher with a fork receives a request message, they keep the fork if it is clean, but give it up when it is dirty. If the philosopher sends the fork over, they clean the fork before doing so.

After a philosopher is done eating, all their forks become dirty. If another philosopher had previously requested one of the forks, the philosopher that has just finished eating cleans the fork and sends it. This solution also allows for a large degree of concurrency, and will solve an arbitrarily large problem. It also solves the starvation problem. The clean / dirty labels act as a way of giving preference to the most 'starved' processes, and a disadvantage to processes that have just 'eaten'. One could compare their solution to one where philosophers are not allowed to eat twice in a row without letting others use the forks in between. Chandy and Misra's solution is more flexible than that, but has an element tending in that direction.

In their analysis they derive a system of preference levels from the distribution of the forks and their clean/dirty states. They show that this system may describe an acyclic graph, and if so, the operations in their protocol cannot turn that graph into a cyclic one. This guarantees that deadlock cannot occur. However, if the system is initialized to a perfectly symmetric state, like all philosophers holding their left side forks, then the graph is cyclic at the outset, and their solution cannot prevent a deadlock. Initializing the system so that philosophers with lower IDs have dirty forks ensures the graph is initially acyclic. See also.

References.

Enabling C developers to write highly concurrent applications is a major focus of Visual Studio 2010. The beta release includes the Concurrency Runtime, parallel libraries, and development tools aimed at addressing several common problems preventing developers from unlocking the performance potential inherent to multicore hardware. Notably, this includes ensuring that developers can identify and take advantage of opportunities for concurrency in their code, productively manage shared state and its side effects, and not having to worry about building low-overhead concurrency infrastructure that is scalable at run time on a variety of hardware. In this article, I'm going to demonstrate how to use the new Asynchronous Agents Library included as part of Visual C 2010 to manage the difficulties that can arise with shared state.

To show you how this works, I will walk through an implementation of a classic concurrency problem: Djikstra's Dining Philosophers. You'll see how the actor-based programming construct of an agent in combination with asynchronous message-passing APIs can be used to provide a correct and easy to understand solution to this problem that doesn't rely directly on threading or synchronization primitives. At a round table sit five philosophers who alternate between thinking and eating from a large bowl of rice at random intervals. Unfortunately for the philosophers, there are only five chopsticks at the table (see Figure 1), and before the philosophers can begin eating, they must acquire a pair of chopsticks.

Since the chopsticks are shared between the philosophers, access to the chopsticks must be protected, but if care isn't taken, concurrency problems arise. Most notably, starvation (pun intended) via deadlock can occur: if each philosopher picks up a chopstick as soon as it is available and waits indefinitely for the other, eventually they will all end up holding only one chopstick with no chance of acquiring another. Most developers will agree that building correct, nontrivial locking is considered challenging and fragile at best.

The Dining Philosophers Problem

As a result, most implementations of the Dining Philosophers problem tend to have implementation details leaked into them. For example, the Philosophers may be aware of the synchronization primitives or of their neighbors' chopsticks.

This becomes particularly problematic if you want to generalize the problem to an arbitrary number of philosophers or refocus an implementation on the problem domain—such as what each philosopher does—rather than focusing on the synchronization and threading primitives. A Chopstick class that is relatively self explanatory. A ChopstickProvider class that will be used to hold the chopsticks on the table and provide them to the philosophers. A Philosopher class that is responsible for thinking and eating and is aware only of its two ChopstickProviders. A PhilospherState enum that can be thinking or eating.

A Table class that contains a set of Philosophers and a set of Chopsticks. Table is responsible for setting the table by placing a single Chopstick in a ChopstickProvider between each Philosopher. Figure 2shows the relationships between the classes. It's important to note that the identifier field mId is a const member variable. I don't want the chopstick to have any state on its own that can get changed accidentally by another thread.

Also notice that the constructor is using an r-value reference in its parameter list (the &&). This is a new language construct in Visual Studio 2010 that is part of the draft C0x standard. An r-value reference here allows the compiler to avoid a copy constructor call and move Id into mId within the Chopstick instance if Id is a temporary variable or r-value.

You can see that, after declaring a chopstick and a chopstickBuffer (an instance of the still undefined ChopstickProvider), Concurrency::send is used to place the address of chopstick into the ChopstickBuffer and Concurrency::receive returns a pointer to a Chopstick from the chopstickBuffer. Concurrency::send is a template method that synchronously places a message in a message block. Concurrency::receive is a template method that returns a message from a message block. Concurrency::receive blocks until a message is available in the message block. The agents library provides a message block called the unboundedbuffer that has the functionality you need.

An unboundedbuffer is a template class that is both a source and a target. It stores a memory-limited number of messages in an internal queue. Messages are removed from the queue when they are requested. You won't need the unbounded quality in this implementation of Dining Philosophers as there is a limited number of chopsticks that will be moving between each chopstick holder.

The key functionality you're interested in from the unboundedbuffer is its move semantics. The agent class is an abstract class that models what is sometimes referred to as an actor pattern or actor-based programming. Agents are intended to be used to facilitate removing dependencies and shared state between active components of an application by having the agents encapsulate state and communicate with each other solely via message passing through a small set of public interfaces. This sounds more complicated than it is, but hopefully you can see the similarities to the Philosopher class.

As I mentioned earlier, the Philosopher class needs to be running on its own thread. Translating this to the terminology of agents this means it needs to be an active task, so Philosopher is going to derive publicly from Concurrency::agent. The Philosopher class also needs to be aware of two ChopstickProviders (one for each hand) and then use them to transition successfully between thinking and eating. The Philosopher class isn't complete yet, but you can see how this is starting to translate into a class synopsis. Implementing PickupChopsticks is significantly more interesting because it manages acquiring and releasing the chopsticks without introducing deadlocks or race conditions.

To implement this I'm going to use another messaging block from the Asynchronous Agents Library called join. Concurrency::join is a message block that waits for messages from multiple sources, potentially of varying types.

Once all messages have been received, it produces a conglomerate message. A join can support sources of the same or multiple types and will acquire messages in a greedy or non-greedy manner. This means that there are four variants of join in the agents library. The Philosopher class will use a single-type non-greedy join. Figure 3shows a simple example of a join in code. //create two chopsticks Chopstick chopstick1('chopstick one'); Chopstick chopstick2('chopstick two'); //create ChopstickProviders to store the chopstick ChopstickProvider chopstickBuffer1; ChopstickProvider chopstickBuffer2; //put a chopstick in each chopstick holder Concurrency::send(chopstickBuffer1, & chopstick1); Concurrency::send(chopstickBuffer2, & chopstick2); //declare a single-type non greedy join to acquire them.

//the constructor parameter is the number of inputs Concurrency::join j(2); //connect the chopstick providers to the join so that messages //sent will propagate forwards chopstickBuffer1.linktarget( & j); chopstickBuffer2.linktarget( & j); //the single type join message block produces a vector of Chopsticks std::vector result = Concurrency::receive(j). Now I'm ready to implement PickupChopsticks. The first thing to notice is that you return a set of chopsticks by returning a vector. To get a pair of chopsticks from the chopstick provider means using a non-greedy join. The non-greedy variant of join waits for an offer of messages from all linked sources, and then, once it has an offer from each source, confirms that it can actually take ownership of the message. This is what prevents deadlock in this example. If I had used greedy as the template parameter for the join, the message would be taken as soon as an offer is made, and sooner or later each Philosopher would have a single chopstick and they would all be deadlocked.

Concurrency::overwitebuffer is a message block that stores a single value that can be overwritten, and it produces a copy of the value when requested. As with the other message blocks, overwritebuffer can be linked to additional targets, and message propagation happens in order. I'll add a public member variable to the Philosopher class that is an overwritebuffer and update it by sending messages to it as the Philosopher transitions from Thinking to Eating. Specifically, this will involve adding a member variable to the Philosopher class. You've already seen everything needed to create the Table class. As mentioned previously, it will contain a set of Philosophers, a set of Chopsticks, and a set of ChopstickProviders.

The Table will be responsible for seating the Philosophers at the table, placing a ChopstickProvider between each of them, and placing a Chopstick in each of the ChopstickProviders. For flexibility I've chosen to make it a template class, and it contains a reference to a list of Philosophers, a vector of Chopsticks, and a vector of Chopstick Holders. Hopefully, it's clear how the agent class and asynchronous message passing that the Asynchronous Agents Library provides can help avoid the difficulties of coordinating access to shared state. I've managed to implement the Dining Philosophers problem without using a single explicit lock and without having to call any threading APIs directly. I've also managed to keep the implementation within the terms of the domain—specifically, I've spent time working with Chopsticks, Philosophers, and Tables as opposed to arrays of integers and semaphores.

What I haven't done yet is added any inherent scalability to the Philosophers. This application as written won't run significantly faster on any more than four cores. But this can be fixed by replacing RandomSpin with something more meaningful, like an algorithm implemented with task-based parallelism using the Parallel Pattern Library (PPL). I encourage you to read about this on the native concurrency blog, where I've got the source code for this article, but where I've also added a few fine-grained parallel thinking algorithms implemented to demonstrate composability between the PPL and the agents library. I've also used the Concurrency Runtime's resource management features to manage the quality of service issues that can arise with an abundance of parallel work.

When processing resources get scarce, I can ensure that the Philosophers still are able to get enough to eat.