Проблема спящего брадобрея
Действие еще одной классической проблемной ситуации межпроцессного взаимодействия разворачивается в парикмахерской. В парикмахерской есть один брадобрей, его кресло и п стульев для посетителей. Если желающих воспользоваться его услугами нет, брадобрей сидит в своем кресле и спит. Если в парикмахерскую приходит клиент, он должен разбудить брадобрея. Если клиент приходит и видит, что брадобрей занят, он либо садится на стул (если есть место), либо уходит (если места нет). Необходимо запрограммировать брадобрея и посетителей так, чтобы избежать состояния состязания. У этой задачи существует много аналогов в сфере массового обслуживания, например информационная служба, обрабатывающая одновременно ограниченное количество запросов, с компьютеризированной системой ожидания для запросов.
Это задание.
Возник вопрос не совсем относящийся к теме: есть ли аналог глобальных переменных в С#? т.е. мне нужно, чтобы переменная, обозначающая кол-во посетителей, была доступна во всей программе.
В дальнейшем, думаю, вопросы еще возникнут - вот и создал тему.
hardcase
27.04.2008 15:17
Цитата(Unknown @ 27.04.2008 11:18)
Проблема спящего брадобрея...
Это задание.
Возник вопрос не совсем относящийся к теме: есть ли аналог глобальных переменных в С#? т.е. мне нужно, чтобы переменная, обозначающая кол-во посетителей, была доступна во всей программе.
Статическое свойство класса тебе поможет.
Код
public class Barbery {
private static int _client_count = 0;
public static int ClientCount {
get { return _client_count; }
}
}
Кстати C# имеет собственный механизм синхронизации:
Код
lock(some_object) {
}
где some_object - это экземпляр ссылочного типа. Синхронизация основана на механизме монитора (эквивалентно семафору).
Цитата
Статическое свойство класса тебе поможет.
точно! туплю ))
а по поводу lock'а в курсе, спасибо
В общем, вот, что у меня получилось:
Код
using System;
using System.Threading;
class Barber
{
public static int barbers = 1;
public static int chairs = 5;
public static int customers = 0;
public static Random r = new Random();
class Customer
{
public bool served;
public Thread thrd;
public Customer(string name)
{
served = false;
thrd = new Thread(new ThreadStart(this.run));
thrd.Name = name;
thrd.Start();
}
public void run()
{
Console.WriteLine(thrd.Name + " пришел.");
do
{
if (barbers > 0) //брадобрей свободен
{
barbers--;
served = true;
}
else
{ //брадобрей занят
if (customers < chairs)
customers++; //клиент ждет
else
{
Console.WriteLine(thrd.Name + " ушел.");
return; //клиент ушел(нет мест)
}
}
customers--;
}
while (!served);
Console.WriteLine(thrd.Name + " обслуживается.");
Thread.Sleep(500);
customers--;
barbers++;
Console.WriteLine(thrd.Name + " обслужен.");
}
}
class MultiThread
{
public static void Main()
{
Customer c1 = new Customer("Клиент #1");
Customer c2 = new Customer("Клиент #2");
Customer c3 = new Customer("Клиент #3");
Customer c4 = new Customer("Клиент #4");
Customer c5 = new Customer("Клиент #5");
Console.ReadKey();
}
}
}
Вроде все работает как задумано - это нормальное решение?
Помоему полная фигня
здесь нет синхронизации...
Да и нет идеи "пробуждения брадобрея".
Вот мой пример, в котором, однако, тоже нет пробуждения. Для этого нужно вместо слипа вешаться на WaitHandle, а клиенты должны его дёргать по приходу.
Код
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
static class BarberRoom {
public static void Main() {
new Client("Клиент #1");
new Client("Клиент #2");
new Client("Клиент #3");
new Client("Клиент #4");
new Client("Клиент #5");
new Barber("Брадобрей #1");
new Barber("Брадобрей #2");
Console.ReadKey();
}
static List<Client> _clientsOnChairs = new List<Client>();
const int ChairsCount = 5;
static Random rnd = new Random();
class Client {
public bool Served;
public bool Serving;
public Client(string name) {
Name = name;
var th = new Thread(delegate() {
if (tryTakeChair()) {
while (!Served) {
Console.WriteLine(name + " ждёт");
Thread.Sleep(500);
}
Console.WriteLine(name + " обслужен");
lock (_clientsOnChairs) {
_clientsOnChairs.Remove(this);
}
} else {
Console.WriteLine(name + " ушел, нет места...");
}
});
th.IsBackground = true;
th.Name = "Client: " + name;
th.Start();
}
public string Name { get; private set; }
bool tryTakeChair() {
lock (_clientsOnChairs) {
if (_clientsOnChairs.Count < ChairsCount) {
_clientsOnChairs.Add(this);
return true;
}
}
return false;
}
}
class Barber {
Client tryGetClient() {
lock (_clientsOnChairs) {
var client = _clientsOnChairs.FirstOrDefault(x => !x.Serving);
if (client != null)
client.Serving = true;
return client;
}
}
public Barber(string name) {
var th = new Thread(delegate() {
while (true) {
var client = tryGetClient();
if (client != null) {
Console.WriteLine(name +" обслуживает "+client.Name);
Thread.Sleep(500 + rnd.Next(1000));
client.Served = true;
Console.WriteLine(name + " закончил");
} else {
Console.WriteLine(name + " спит");
Thread.Sleep(5000);
Mutex
}
}
});
th.IsBackground = true;
th.Name = "Barber: " + name;
th.Start();
}
}
}