
- •Кафедра информатики
- •Курсовая работа
- •По программированию
- •Задача об обедающих мудрецах
- •Оглавление
- •1. Постановка задачи
- •1.1. Задание Задача об обедающих мудрецах
- •1.2. Алгоритмическое решение задачи
- •1.2.1 Решение задачи
- •1.3. Контрольные примеры
- •1. Официант
- •2. Иерархия ресурсов
- •3. Монитор
- •2. Решение задачи
- •2.1. Выбор средств реализации
- •2.2. Описание основных классов
- •2.3 Интерфейс приложения
- •3. Тестирование приложения
- •3.1. Контрольный робот
- •3.2. Работа приложения на контрольных тестах
- •3.3. Результаты работы
2.3 Интерфейс приложения
Интерфейс приложения очень прост и дружелюбен к пользователю. Нет никаких меню, кнопок или полей для ввода, в которых пользователь мог бы запутаться, есть лишь красочная картинка, демонстрирующая состояния философов (думает/голоден/хочет ухватить вилку/кушает), которой вполне достаточно для моделирования проблемы обедающих философов. Работа приложения показана на рисунке 3.
Рисунок 3. Разгар обеда у 5 философов.
На рисунке видно, что философ на 12 часов получил обе вилки (объекты Fork) и приступил к трапезе, философ на 2 часа проголодался и, взяв одну вилку, обижено тянет руку к философу на 12 часов, поджидая вилку. Философ на 5 часов сыт и размышляет о бытие, философ на 7 часов, аналогично философу на 12 часов, получил (заблокировал) обе вилки и кушает. Философу на 10 часов не повезло и пока у него самое плохое положение: нет ни мыслей о создании мира, так как желудок пуст, ни вилок и ему лишь остаётся ждать своей очереди.
Когда пользователю надоест лицезреть обед философов или ему и самому захочется кушать, то он может завершить приложение привычным ему образом кликнув по крестику в правом углу.
3. Тестирование приложения
3.1. Контрольный робот
Для того чтобы протестировать работу приложения воспользуемся распространённым подходом под названием юнит-тестирование и конкретным фреймворком - JUnit.
Так как юнит-тестирование подразумевает проверку компонентов по отдельности, то мы можем написать тесты проверяющие работу вилок и философов отдельно, что мы и сделаем.
Проверить работу класса Fork мы можем следующим образом:
1) Проверим, что вилка изменяет своё состояние, когда её берёт профессор
@Test
public void forkLockTest(){
Fork fork = new Fork();
fork.lock();
assertTrue(fork.locked());
}
@Test
public void forkUnlockTest(){
Fork fork = new Fork();
fork.lock();
fork.unlock();
assertFalse(fork.locked());
}
2) Проверим, что Fork может разблокировать лишь тот поток, что его заблокировал
@Test
public void forkUnlockByOwnerOnlyTest(){
final Fork fork = new Fork();
fork.lock();//заблокирован текущим потоком
Thread th = new Thread(){
@Override
public void run(){
fork.unlock();//пытаемся разблокировать другим потоком
}
};
//усыпляем поток, чтобы другой точно выполнился
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
//проверяем что Fork по прежнему заблокирован
//так как другой поток не смог снять с него блокировку
assertTrue(fork.locked());
}
Проверить работу класса Philosopher можно так:
1) проверим, что философ постоянно меняет своё состояние и за 15 секунд он точно должен пройти все свои возможные состояния
@Test (timeout= 15000)
public void philosopherChangeStates() throws InterruptedException{
Fork fork1 = new Fork();
Fork fork2 = new Fork();
Philosopher philosopher = new Philosopher(1, fork1, fork2);
philosopher.start();
while(philosopher.state() != Philosopher.THINKING)
Thread.sleep(100);
while(philosopher.state() != Philosopher.EATING)
Thread.sleep(100);
while(philosopher.state() != Philosopher.THINKING)
Thread.sleep(100);
}
2) Проверим, что философ, когда думает, освобождает вилки, а когда кушает – блокирует их
@Test(timeout = 15000)
public void philosopherTakeAndReleaseForks() throws InterruptedException{
Fork fork1 = new Fork();
Fork fork2 = new Fork();
Philosopher philosopher = new Philosopher(1, fork1, fork2);
philosopher.start();
while(philosopher.state() != Philosopher.THINKING)
Thread.sleep(100);
//если философ думает, то вилки должны быть свободны
assertFalse(fork1.locked());
assertFalse(fork2.locked());
while(philosopher.state() != Philosopher.EATING)
Thread.sleep(100);
//если философ кушает, то вилки должны быть заняты
assertTrue(fork1.locked());
assertTrue(fork2.locked());
while(philosopher.state() != Philosopher.THINKING)
Thread.sleep(100);
//когда философ наелся, то он должен был положить (освободить) вилки
assertFalse(fork1.locked());
assertFalse(fork2.locked());
}