Консультация № 187011
22.12.2012, 11:04
100.60 руб.
0 0 0
Здравствуйте! Прошу помощи в следующем вопросе:
Вот текст исходной задачи про обедающих философов:

Имеется столовая комната, в которой на середине круглого стола столе стоит блюдо с макаронами. У стола стоят 5 стульев, на столе имеются 5 тарелок, около каждой из тарелок слева лежит вилка. Для того, чтобы есть макароны, надо сесть на стул и взять две вилки.

Пять философов ходят и размышляют. Время от времени каждый из них ощущает голод, заходит в столовую, садится на стул, берет левую, затем правую вилку (если таковые свободны) и ест макароны. Потом кладет вилки и выходит из столовой.

Возможна ситуация, когда все пять философов одновременно занимают пять стульев и каждый берет по одной (левой) вилке, и в этом случае ни один из них не может начать есть. Другими словами, возникает тупиковая ситуация (dead lock).

Задача состоит в реализации схемы, позволяющей обходить такую тупиковую ситуацию. В данном случае возможны различные способы решения. Например:

• у столовой есть хозяин, который пропускает философа к столу только в том случае, если там менее 4-х занятых мест (количество занятых мест < 4);
• каждый философ не может брать левую вилку, если правая занята, т.е. он может брать только две вилки одновременно;
• и т.д.
Реализованная модель должна демонстрировать тупик и работу средств борьбы с ним.
Также программа должна работать при любом количестве философов(то есть хотя бы выводить что-то на экран)

Имеется реализация на C#,код которой привожу ниже,в которую нужно внести изменения,исправить её,чтобы работала правильно.То есть сначала философ задумался,потом проголодался и только затем сел кушать.А пока при запуске,просматривая работу программы,можно увидеть ситуации,когда философ задумался,ещё вроде бы не проголодался,но "ХОП" уже сел кушать

Приложение:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;

namespace lab3
{
namespace ConsoleApplication2
{
class Program
{
public const bool DeadLock = false;
static void Main(string[] args)
{
const int N = 5;
List<Philosopher> ph = new List<Philosopher>(); // создание списка для философов
List<Thread> t = new List<Thread>(); // создание списка для потоков
Table table = new Table(N); // создание стола
table.toOut(3); // выводить вилки-стулья
if (N==0)
{
Console.WriteLine("Недопустимое количество философов!");
Console.ReadKey();
}
else
for (int i = 0; i < N; i++) // цикл,заполняющий списки
{
ph.Add(new Philosopher((i + 1).ToString()));
t.Add(new Thread(ph[i].Start));
t[i].Start(table); // запуск старта потоком
}

}
}

public class Philosopher
{
bool isHunger = false; // запуск старта потоком
string philosopherName;
Semaphore owner = new Semaphore(3, 3);
/// <summary>
/// конструктор для экземпляра класса "Философ"
/// </summary>
/// <param name="Name">Имя философа</param>
public Philosopher(string Name) // конструктор философа
{
philosopherName = Name;
}
/// <summary>
/// рассматривает возможность "Взять вилку"
/// </summary>
/// <param name="table"></param>
void GetFork(Table table) // функция взять вилку
{
int first = 0; // 1 вилка
int second = 0; // 2 вилка
for (int i = 0; i < table.fork.Count; i++) // цикл по количеству вилок
{
lock (table.chair[i])
while (!table.chair[i].Use) // пока стул не используется
{
table.chair[i].Use = true; // занять стул
table.chair[i].Mark = philosopherName; // пометить,кто занял стул
table.toOut(2); // вывести стулья
first = i; // выбрать соответствующую стулу вилку
lock (table.fork[first])
while (!table.fork[first].IsUsing)
{
table.fork[first].IsUsing = true;
table.fork[first].Mark = philosopherName;
table.toOut(1);
second = ((first + 1) > table.fork.Count - 1) ? 0 : first + 1; // выбираем вторую вилку
lock (table.fork[second]) // синхронизация по вилке
if (!table.fork[second].IsUsing) // если вилка свободна
{
table.fork[second].IsUsing = true; // занять вилку
table.fork[second].Mark = philosopherName; // помечаем,кто взял вилку
table.toOut(1); // вывод вилок

Console.WriteLine("Философ {0} \t кушает.", philosopherName); // фил взял 2 вилки.Выводим,кто ест
if (!Program.DeadLock)
Console.WriteLine("Философ {0} \t покушал.", philosopherName); // пишем,что философ поел
lock (table.fork) // синхронизация по вилке
{
table.fork[second].IsUsing = false; // кладет 2 вилку
table.fork[second].Mark = ""; // обнуляем метку
}
table.toOut(1); // вывод вилок
lock (table.fork) // синхронизация по вилке
{
table.fork[first].IsUsing = false; // освобождаем первую вилку
table.fork[first].Mark = ""; // обнуляем метку вилки
}
table.toOut(1); // вывод вилок
lock (table.chair) // синхронизация по стулу
{
table.chair[i].Use = false; // освободить стул
table.chair[i].Mark = ""; // очистить метку
}
table.toOut(2); // вывод стульев
ChangeStatus(); // меняем статус
break;
}
break;

}
break;
}
}
}
/// <summary>
/// задает начало жизни философа
/// </summary>
/// <param name="obj"></param>
public void Start(object obj)
{
if (!isHunger) // если не голодный
{
Console.WriteLine("Философ {0} \t задумался.", philosopherName);
}
for (int i=0; i<20; i++);
{
ChangeStatus();
if (!Program.DeadLock)
if (isHunger) // если голоден
{
if (!Program.DeadLock)
owner.WaitOne();
GetFork((Table)obj); // пытается сесть за стол
if (!Program.DeadLock)
owner.Release();
}
}
Console.ReadKey();
}
/// <summary>
/// Если голоден - стал сытым и начал думать. Иначе - стал голоден.
/// </summary>
void ChangeStatus()
{
isHunger = !isHunger; // меняем статус
if (!isHunger) // если не голоден,пишем,что думает
Console.WriteLine("Философ {0} \t задумался.", philosopherName);
else
Console.WriteLine("Философ {0} \t проголодался.", philosopherName); // если голоден,пишем,что проголодался
}
}
/// <summary>
/// Класс стол. собирательное понятие. включает в себя стулья и вилки.
/// </summary>
public class Table // класс стола
{
public List<Fork> fork = new List<Fork>(); // создание списка вилок
public List<Chair> chair = new List<Chair>(); // создание списка стульев
public Table(int N)
{
for (int i = 0; i < N; i++) // цикл по количеству вилок и стульев
{
chair.Add(new Chair()); // добавить стулья в список
fork.Add(new Fork()); // добавить вилки в список
}
}

public void toOut(int i) // функция вывода
{
lock (this)
{
switch (i) // передаем управления одному из операторов case
{
case 1: forkOut(); break; // вывод вилок
case 2: chairOut(); break; // вывод стульев
case 3: forkOut(); chairOut(); break; // вывод стулья-вилки
default: forkOut(); chairOut(); break; // если ничего не введено,то вилки-стулья
}
}
}
private void forkOut() // функция вывод вилок
{
Console.Write("\tВилки: \t");
foreach (Fork temp in fork) // для каждой вилки из списка
{
string toOut = (temp.IsUsing) ? temp.Mark : "-"; // (формируем строку toOut) если вилка исп-ся,то пишем кем, иначе пишем -
Console.Write(toOut); // выводим туАут
}
Console.WriteLine(); // Записывает текущий признак конца строки в стандартный выходной поток
}
private void chairOut() // функция вывод стульев
{
Console.Write("\tСтулья: ");
foreach (Chair temp in chair) // для каждого стула из списка
{
string toOut = (temp.Use) ? temp.Mark : "-"; // формируем туАут
Console.Write(toOut); // выводим туАут
}
Console.WriteLine(); // Записывает текущий признак конца строки в стандартный выходной поток
}
}

public class Chair
{
bool use = false; // не используется
string mark = ""; // обнуляем метку
public string Mark // конструктор метки
{
get { return mark; } // получить значение метки
set { mark = value; } // установить значение метки
}
public bool Use // конструктор использования стула
{
get { return use; }
set { use = value; }
}
}

public class Fork
{
bool isUsing = false;
string mark = "";
public string Mark
{
get { return mark; }
set { mark = value; }
}
public bool IsUsing
{
get { return isUsing; }
set { isUsing = value; }
}
}
}
}



Обсуждение

Форма ответа