What is the problem of gluttonous philosophers?

When talking about concurrent programming, they always cite 3 Classic problems / concurrency Models:

  1. producers and consumers
  2. readers and writers
  3. gluttonous philosophers (or philosophers ' dinner)

I searched here on the site but at no time did I find explaining what this problem is.

My doubts then are:

  • what is the problem of gluttonous philosophers? (more focused on statement / metaphor of the problem)
  • What does the philosophers ' dinner actually shape? (more focused on the technical thing than this problem is, leaving the metaphor aside)
  • how important is it to a programmer? when should a programmer directly worry about this problem?
  • is there something real and everyday that we run into this problem without having knowledge? I don't know, in a database?
Author: Bruno Costa, 2018-03-16

4 answers

Philosophers Dinner

Problem description:

  • five philosophers are sitting around a circular table for dinner.
  • each philosopher has a plate for eating noodles.
  • in addition, they feature hashis instead of forks
  • each needs 2 hashis
  • between each pair of dishes there is only one hashi.
  • Hashis need to be shared in a way synchronized

insert the description of the image here

Problem rules:

  • philosophers eat and think, alternately
  • when they eat, they take only one hashi at a time
  • if you can catch both, eat for a few moments and then drop the hashis

The X of the question : How to prevent them from getting stuck?

insert the description of the image here

Solutions

#define N 5 /* número de filósofos */

void filosofo(int i) /* i: número do filósofo, de 0 até 4 */
{
    while(true){
         pense();  /* Filosofo está pensando */
         pegue_hashi(i); /* pegue o Hashi esquerdo */
         pegue_hashi((i+1) % N); /* pegue o Hashi direito; % é o operador módulo */
         coma(); /* yum-yum, spaghetti rs */
         largar_hashi(i) ; /* larga o hashi esquerdo*/
         largar_hashi((i+1) % N); /* larga o hashi direito */
    }
}

Does the above code work?

In pegue_hashi(): If all philosophers take the hashi from the left, none will take the hashi from the right - DEADLOCK

See

insert the description of the image here

And how to solve?

After taking the hashi on the left, the philosopher checks if the one on the right is free. If it's not, return the hashi you picked up, wait a bit and try again.

What is the problem with this solution?

If all philosophers take the hashi from the left at the same time:

  • will see that the one on the right is not free
  • will drop their hashi and and wait
  • will pick up the left hashi again
  • will see that the one on the right is not free
  • ... (Infinite Looping)

Then the problems that should be avoided:

  • Deadlock-all philosophers take a single hashi at the same time
  • Starvation - philosophers endlessly pick up hashis simultaneously.

And now? What do I need to do?

We could make them wait a random time

  • reduces the chance of starvation
  • in most applications, trying again is no problem
  • via ethernet, this is exactly what is done with sending packets
  • What if this process is used in nuclear power plant safety control? Is that a good idea?

We go back to another question : How to avoid multiple attempts?

Using traffic lights would solve the problem, See:

#define N 5 /* número de filósofos */
semaphore mutex = 1;

void filosofo(int i) /* i: número do filósofo, de 0 até 4 */
{
    while(true){
         pense();  /* Filosofo está pensando */
         down(&mutex); /* requisita o semáforo */
         pegue_hashi(i); /* pegue o Hashi esquerdo */
         pegue_hashi((i+1) % N); /* pegue o Hashi direito; % é o operador módulo */
         coma(); /* yum-yum, spaghetti rs */
         largar_hashi(i) ; /* larga o hashi esquerdo*/
         largar_hashi((i+1) % N); /* larga o hashi direito */
         up(&mutex); /* Libera o semáforo para os outros */
    }
}

Theoretically, it is a suitable solution in practice, however, it has a performance problem:

  • only a philosopher can eat at a given time
  • with 5 hashis, we should allow 2 philosophers to eat at the same time

But after all, how will I solve without deadlocks or starvation and with maximum parallelism to an arbitrary number of philosophers?

Use a state – arrangement to identify whether a philosopher is eating, thinking, or hungry (thinking of picking up the hashis).

  • a philosopher can only eat (state) if none of the neighbors are eating
  • use a semaphore arrangement, one per philosopher
  • hungry philosophers can be blocked if hashis are busy

Rewriting the Code:

#define N 5 /* número de filósofos */
#define LEFT /* número do vizinho da ESQUERDA */
#define RIGHT /* número do vizinho da DIREITA */
#define PENSANDO 0 /* Filósofo está pensando */
#define FAMINTO 1 /* Filósofo está faminto */
#define COMENDO 2 /* Filósofo está comendo */
typedef int semaphore; /* o semáforo é um tipo especial de int  */
int state[N]; /* Array para acompanhar o estado de todos*/
semaphore mutex = 1; /* exclusão mútua para regiões críticas */
semaphore s[N]; /* um semáforo por filósofo */

void filosofo(int i) /* i: número do filósofo, de 0 até 4 */
{

   while(true){
      pense();  /* Filosofo está pensando */

      pegue_hashi(i); /* pegue os dois Hashis */

      coma(); /* yum-yum, spaghetti rs */

      largar_hashi(i) ; /* larga os dois Hashis */             
  }
}

void pegue_hashi(int i){ /* i: numero do filosofo, de 0 até N-1 */
   down(&mutex); /* entra na região crítica */
   state[i] = FAMINTO; /* recorda o fato que o filósofo i está faminto */
   testa(i); /* tenta adquirir as DUAS hashis */
   up(&mutex); /* sai da região crítica */
   down(&s[i]); /* bloqueie se os hashis não foram adquiridos */ 
}

void largar_hashi(i){ /* i: numero do filosofo, de 0 até N-1 */
   down(&mutex); /* entra na região crítica */
   state[i] = PENSANDO; /* recorda o fato que o filósofo i está faminto */
   testa(LEFT); /* veja se o vizinho da esquerda pode agora comer */ 
   testa(RIGHT ); /* veja se o vizinho da direita pode agora comer */
   up(&mutex); /* sai da região crítica */
}

void testa(i){ /* i: numero do filosofo, de 0 até N-1 */
   if(state[i] == FAMINTO && state[LEFT] != COMENDO && state[RIGHT] != COMENDO ){
      state[i] = COMENDO;
      up(&s[i]); /* libera se os hashis foram adquiridos */
    }
}

  • what the philosophers ' dinner indeed models?

Useful for modeling processes that compete for exclusive access to a limited number of resources.

  • how important is it to a programmer? when a programmer should you worry directly about this problem?

The advantages of concurrent programming is the increased performance of the program, due to the increase in the amount of tasks that can be performed during a certain period of time. We concurrent access to shared data and resources can create a situation of inconsistency of these same resources, this is because the various instances access and manipulate simultaneously, giving situations of inconsistency and failure. So for a routine or program to be consistent, mechanisms are needed that ensure the orderly and correct execution of cooperating processes.

Source of answer:

 31
Author: Don't Panic, 2018-03-21 13:55:35

Problem of gluttonous philosophers (philosophers ' Dinner):


Let's imagine a round table with 5 chairs and in each of the chairs sits a philosopher. On this table there are 5 plates of spaghetti and 5 forks, and in front of each plate of spaghetti will be a philosopher. However, to be able to eat each philosopher will have to use 2 forks.

That is, with 5 forks on the table and 5 philosophers, they can only eat 2 philosophers at the same time getting 1 fork left over.

And for them to be able to eat all at the same time it would take 10 forks.

Philosophers ' dinner

Problem: If everyone wants to eat and take a fork, every philosopher will have a fork but none of them you'll be able to eat. We will have a deadlock, for all philosophers will be eternally waiting for the other fork, giving themselves a deadlock. Against the background of this dinner happens when all philosophers are prevented from eating, as they have no conditions for just.

DeadLock: it occurs when two or more processes are prevented from continuing, by waiting for a feature that will never be available.


In technical terms, each philosopher represents a process and each fork a resource and there is a competition for resources, being therefore considered one of the models of competition. To prevent this from happening it is necessary to synchronize the processes, so that when one is using a certain resource another process will have to wait to use this same feature.


Importance for a programmer: This is an important situation for a programmer, to be able to visualize a deadlock situation and to realize the importance of the good use of synchronization mechanisms.


Real situations: The only real situation I have encountered is the case of traffic light signs, let's imagine that these were not synchronized, what would happen is that eventually these would turn the two greens and there would be accidents, so it is essential that these are synchronized to avoid accidents and to allow less traffic.

Search sources:

First

Second

Third

Fourth

Fifth

 24
Author: IdkWhy, 2018-03-16 14:27:51

The problem of gluttonous philosophers has already been explained by @idkWhy. I just wanted to supplement his answer since in my opinion there is a little more knowledge to be drawn from the proposed problem.

This answer takes into account other narratives that are not part of the problem as it was originally proposed in 1965 by Dijkstra. Usually the focus always falls to the problem of obtaining resources, however I would also like to explore narratives where there is no any problem in obtaining resources.

As explained, there are 5 forks (a feature, let's imagine a synchronization object) on the table and 5 philosophers (one thread). Each philosopher needs 2 forks to eat. As all philosophers are hungry (threads are running code) each philosopher takes a fork (acquires the resource).

1. Philosophers well behaved, being for this reason a non-problem

But so far there is no problem, because a philosopher has the brilliant idea of dropping his fork, in return, the philosopher who wants his fork it pays you dinner (i.e. threads negotiate with an arbiter, who should get the feature). As soon as this philosopher finishes eating (freeing the resource), all the other philosophers they will run looking for the fork (acquire the resource). Like philosophers they are very competitive so they decided that those who manage to get the fork first eat first. Let's give an example?

Filosofo = F
Garfo = G

F1 pega o G1
F2 pega o G2
F3 pega o G3
F4 pega o G4
F5 pega o G5

F2 decide largar o seu garfo.
F4 decidiu pagar o jantar a F2 
F4 obteve G2
F4 acabou de jantar e largou G2 e G4

F1, F2, F3, F5 vao pegar os garfos G2 e G4 o mais rapidamente possível.
Apenas dois deles terao sucesso.

A história repete-se de forma similar a quando F4 obteve o seu garfo, excepto que é de notar
que a medida que os filósofos vão acabando o seu jantar vai havendo mais garfos disponíveis.

This unnecessarily long and complicated narrative would be a possible solution so that philosophers can eat and illustrates that there because there are only 5 forks for 5 philosophers (and each philosopher need two forks) does not mean that they you cannot have dinner, of course, in a properly organized process.

2. Proper identification of the problem

So let's make a narrative of an unorganized process, to properly identify whom is the problem:

Philosophers sit at the table and begin to think. How hungry are they, as soon as the food comes to the table, they try to catch the 2 forks near themselves. Some philosophers decide to start by taking the fork on the left and others decide the fork on the right.

Cenar 1: Soon by bad luck on the first attempt all the philosophers got a single fork and never they have no idea how to eat because they wait eternally for the other philosophers to leave their fork.

Scenario 2: A Philosopher consguiu get 2 forks but as soon as he finishes eating he gets spammy with the confusion of all other philosophers, they are waiting for the wrong fork.

2.1. Problem exemplification (c#)

private static Random r = new Random(500);
private static int numeroFilosos = 200;
static void Main(string[] args)
{
    var garfos = Enumerable.Range(0, numeroFilosos)
        .Select(i => new Mutex(false))
        .ToArray();

    var filosofos = Enumerable.Range(0, numeroFilosos)
        .Select(i => new Thread(ComeOJantar)
        {
            IsBackground = false
        })
        .ToArray();
    for (int i = 0; i < filosofos.Length; i++)
    {
        //Os filosofos tem conhecimento dos garfos que estao ao seu lado
        filosofos[i].Start(Tuple.Create(garfos[i], garfos[(i+1)% filosofos.Length]));
    }
    Thread.Sleep(TimeSpan.FromSeconds(2));
    Parallel.ForEach(filosofos, f => f.Join());
    Console.WriteLine("Todos os filosofos comeram");
}

private static void ComeOJantar(object o)
{
    var dados = o as Tuple<Mutex, Mutex>;
    var garfo1 = dados.Item1;
    var garfo2 = dados.Item2;

    //Os filosofos obtem os garfos á pressa, uns obtem o da direita primeiro e outros
    //o da esquerda.
    if (r.NextDouble() > 0.5)
    {
        garfo1.WaitOne();
        garfo2.WaitOne();
        Thread.Sleep(TimeSpan.FromSeconds(1));
        //Os filosofos também nao tem cuidado em qual garfo poisar primeiro
        garfo1.ReleaseMutex();
        garfo2.ReleaseMutex();
    }
    else
    {
        garfo2.WaitOne();
        garfo1.WaitOne();
        Thread.Sleep(TimeSpan.FromSeconds(2));
        //Os filosofos também nao tem cuidado em qual garfo poisar primeiro
        garfo2.ReleaseMutex();
        garfo1.ReleaseMutex();
    }
}

3 philosophers with table label.

Once again we explore an organized process. This time the philosophers have table etiquette and decide to always take the Left Fork first.

Contudo it is still possible that philosophers get only the left fork. For this reason, they decide to drop their fork and think for a while so that their neighbor, if interested, can get their fork

3.1. Example of a solution, using ordered resource acquisition (c#)

The previous solution did not take into account the case where the philosophers all got the fork to their left

private static void ComeOJantar(object o)
{
    var dados = o as Tuple<Mutex, Mutex>;
    var garfoEsquerda = dados.Item1;
    var garfoDaDireita = dados.Item2;

    garfoEsquerda.WaitOne(); //os filosofos obtem o garfo da esquerda

    //este sleep serve apenas para efeitos ilustrativos
    //ele ajuda a simular a situação em que todos os filósofos 
    //conseguem obter o garfo da esquerda
    Thread.Sleep(TimeSpan.FromSeconds(5));

    //Os filosofos tentam agarrar o garfo da direita o mais rápidamente possivel
    //Contudo todos os garfos já estao ocupados
    while (!garfoDaDireita.WaitOne(TimeSpan.FromMilliseconds(50)))
    {
        //O filosofo decide largar o seu garfo e espera que o seu 
        //vizinho vá buscar o seu garfo
        garfoEsquerda.ReleaseMutex();

        //Este sleep faz parte da solução. 
        //Ele evita que o filosofo adquira o mesmo garfo imediatamente após o ter largado
        Thread.Sleep(TimeSpan.FromMilliseconds(r.Next(1, 5) * 100));

        garfoEsquerda.WaitOne();
    }
    //Neste momento os filosofos tem ambos os garfos e podem comer
    Thread.Sleep(TimeSpan.FromSeconds(1));
    garfoDaDireita.ReleaseMutex();
    garfoEsquerda.ReleaseMutex();
}

4. Victory victory, the story is over

The moral of this problem is that in competing environments you have be careful in what order you acquire resources. If you work in single-thread environments (e.g. nodejs) then you will never have problems regarding resource acquisition.

In principle if you use a transitional database, the database solves this problem for you. at least MSSQL resolves .

The SQL Server Database Engine automatically detects deadlock cycles within SQL Server. The Database Engine chooses one of the as sessions a deadlock victim and the current transaction is terminated with an error to break the deadlock.

In free translation:

The SQL server Database detects deadlocks inside SQL Server. It chooses one of the sessions as the victim of deadlock and the current transaction is terminated with an error to break the deadlock

TL; DR

  1. the problem of philosophers is a non-problem, if the process is properly organized.
  2. to really exist problem it is necessary to acquire resources in a non-orderly manner
  3. in particular, the acquisition of resources in different order is reported and viewed relatively simply
  4. the moral of the story is that it will normally be sufficient to acquire and release resources in the same order
 12
Author: Bruno Costa, 2018-03-20 19:42:09

Answer 2 (new)

Complementing the general answers, I put an addendum, which in my view is considerable, and also practically reinforcing my first answer:

As stated in Bruno Costa's answer, the problem in question was formulated by Edsger W. Dijkstra in 1965.

With that, going back there where there were not numerous programming languages as currently, and also more limited language resources, really it is a simple exercise to show problems in the synchronizations (as it is said in the source itself).

Today with the wide range of resources and languages we have, the question is left in parts branched by ourselves due to ideas beyond the proposed context (a simple synchronization exercise).

In Wikipedia, if you have all the history and solutions of the problem:

Dining philosophers problem

  • hierarchy solution of resources

Which was the original solution proposed by Dijkstra, treating philosophers as processes and forks as resources.

  • arbitration solution

Solution where one has an" arbiter " in the context, for example the waiter, who will give the permissions and orders to the philosophers.

  • Chandy / Misra Solution

In 1984, K. Mani Chandy and J. Misra, gave the solution similar to arbitrary, but counting the philosophers talking to each other, using "requests", that is, each philosopher would request the fork to his neighbor on the right and to the left, thus allowing, would have the 2 tools, and if not succeeding, could wait for the request of another and borrow his own fork, not falling into deadlock.


Answer 1 (old) [-2]

I will respond briefly from my point of view, with my words, that is, the line of thought is the same, but sometimes clear that we can have other ways.

What is the problem of gluttonous philosophers?

In my view, simply a great analogy, between process X resource, task x execution, or even more examples that we managed to fit.

What does the philosophers ' dinner actually shape?

A pretty hefty problem for a logical question. Although, if applied in logic it would be easier to solve, since we control all the paths.

How important it is to a programmer?

First of all, right from the beginning in "where to begin to resolve the situation" and after, which forms, and which one is best.

When should a programmer directly worry about this problem?

There is the " X " of the question in my view. I understand that, very briefly, we must always have well defined the algorithm, so as not to enter the deadlock, as in the answer above.

That is, the importance of setting priorities, in short example, a list of tasks that must be carried out but depends on each other (it would be the philosophers, who depend on the forks), and then if all need to be executed, what is the priority, that is, who has the power to pass in front ? Or for example, on a scale from 0 to 100, what is the priority level of that ?

Is there something real and everyday that we run into this problem without having knowledge? I don't know, in a database?

An example with bank: what is deadlock in SQL Server?

If anyone understands differently, please comment !

 4
Author: rbz, 2018-03-21 09:56:29